Compare commits

...

325 Commits

Author SHA1 Message Date
Brian Smith
5219606c5f feat: use frontend-plugin-framework to provide a FooterSlot 2024-06-06 15:04:59 -03:00
ayesha waris
e314de2042 feat: implemented notification preference UI for cadence (#1033)
* feat: implented notification preference UI for cadence

* refactor: refactored code

* refactor: refactored code

* refactor: clean code after adding email cadence

* refactor: refactored and restructured notificationPreferences page

* refactor: refactored and implemented mobile view

* fix: fixed disabled for email cadence

* refactor: resolved spaces and changed font size class

* refactor: resolved conflicts

---------

Co-authored-by: Awais Ansari <awais.ansari63@gmail.com>
2024-05-07 16:54:15 +05:00
renovate[bot]
fc329fe9c2 chore(deps): update dependency @testing-library/jest-dom to v6.4.5 2024-05-06 07:21:07 +00:00
Ahtisham Shahid
aea3a7c830 fix: updated notification app name to grading (#1041) 2024-05-06 12:17:34 +05:00
Ahtisham Shahid
35b5459dec fix: removed core type from ora app (#1040) 2024-04-30 18:09:28 +05:00
renovate[bot]
2b82ac9faf fix(deps): update react-router monorepo to v6.23.0 2024-04-29 07:39:32 +00:00
renovate[bot]
24ad8851e6 fix(deps): update dependency core-js to v3.37.0 2024-04-29 04:53:22 +00:00
renovate[bot]
b62645349e fix(deps): update dependency @edx/frontend-platform to v8.0.1 2024-04-29 04:52:47 +00:00
Awais Ansari
d2c160b771 Merge pull request #1035 from openedx/ahtisham/regen-lock-file
chore: regenerated package lock file
2024-04-25 15:48:05 +05:00
Ahtisham Shahid
6e39072334 chore: regenerated package lock file 2024-04-25 15:02:44 +05:00
Bilal Qamar
245bf9aa6b feat: updated frontend-build & frontend-platform major versions (#958)
* chore: bumped jest to v29, updated snapshots

* refactor: switched frontend-build to openedx, updated snapshots

* refactor: added overrides to resolve dependency issues

* refactor: updated frontend-build to the version which has eslint alpha synced with master

* refactor: updated frontend-build to alpha branch

* refactor: updated frontend-build to alpha version

* refactor: updated overrides

* feat: updated build and platform major versions, along with edx packages
2024-04-24 18:02:11 +05:00
renovate[bot]
b8a4163629 fix(deps): update dependency @edx/frontend-platform to v7.1.4 2024-04-22 06:20:33 +00:00
Ahtisham Shahid
a5730b625a feat: added new messages for ora notification (#1026) 2024-04-22 11:16:52 +05:00
renovate[bot]
f03ac8b6d9 fix(deps): update dependency @edx/frontend-component-footer to v13.0.5 2024-04-15 06:54:54 +00:00
renovate[bot]
9e72f1c9e9 fix(deps): update dependency qs to v6.12.1 2024-04-15 04:21:13 +00:00
ayesha waris
9693d938c6 Revert "feat: implented notification preference UI for cadence (#1013)" (#1029)
This reverts commit a266e3dca9.
2024-04-05 16:53:13 +05:00
Muhammad Ammar
f45bb43064 Merge pull request #1027 from openedx/ammar/add-more-languages
feat: add new languages
2024-04-04 23:50:13 +05:00
muhammad-ammar
32f9804e4a feat: add new languages 2024-04-04 14:38:43 +05:00
renovate[bot]
feef40f6d0 fix(deps): update dependency @edx/frontend-platform to v7.1.3 2024-04-01 04:04:33 +00:00
ayesha waris
a266e3dca9 feat: implented notification preference UI for cadence (#1013)
* feat: implented notification preference UI for cadence

* refactor: refactored code

* refactor: refactored code

* refactor: clean code after adding email cadence

* refactor: refactored and restructured notificationPreferences page

* refactor: refactored and implemented mobile view

---------

Co-authored-by: Awais Ansari <awais.ansari63@gmail.com>
2024-03-25 20:52:22 +05:00
renovate[bot]
6cc50a983e fix(deps): update dependency core-js to v3.36.1 2024-03-25 06:48:12 +00:00
Samir Sabri
16caae04af feat!: remove Transifex calls for OEP-58 (#887) 2024-03-18 15:05:34 -04:00
renovate[bot]
2452d09913 fix(deps): update dependency @edx/frontend-platform to v7.1.2 2024-03-18 07:30:38 +00:00
renovate[bot]
b7f2a1f689 fix(deps): update dependency @edx/frontend-component-footer to v13.0.4 2024-03-18 05:02:34 +00:00
renovate[bot]
2416782eca fix(deps): update dependency qs to v6.12.0 2024-03-11 07:03:49 +00:00
renovate[bot]
5d0a428bdf fix(deps): update react-router monorepo to v6.22.3 2024-03-11 07:02:50 +00:00
renovate[bot]
fe4909ce07 fix(deps): update dependency @edx/frontend-platform to v7.1.1 2024-03-11 04:24:44 +00:00
renovate[bot]
9d61e836a5 fix(deps): update dependency @edx/frontend-component-footer to v13.0.3 2024-03-11 04:24:18 +00:00
renovate[bot]
891e28ec59 chore(deps): update dependency @testing-library/jest-dom to v6 2024-03-04 16:55:48 +00:00
ayeshoali
5ec4893f47 fix: fixed text appearance 2024-03-04 17:36:37 +05:00
renovate[bot]
c5c0cf5392 fix(deps): update react-router monorepo to v6.22.2 2024-03-04 06:17:55 +00:00
Saad Yousaf
350c2080ec fix: add correct strings for new course update notifications 2024-02-27 13:04:17 +05:00
renovate[bot]
44b718ad02 fix(deps): update dependency core-js to v3.36.0 2024-02-26 06:37:11 +00:00
renovate[bot]
97333ada47 fix(deps): update react-router monorepo to v6.22.1 2024-02-19 06:43:12 +00:00
ayesha waris
3467534bc7 feat: make notification channel headings clickable in notification (#983)
* feat: make notification channel headings clickable in notification preferences

* chore: refactoring the code for readability according to ESLint

* refactor: onChannelToggle updated for readability

* refactor: onChannelToggle updated

* refactor: further simplified onChannelToggle

* perf: updated onChannelToggle to improve performance

* fix: fixed lint error

---------

Co-authored-by: eemaanamir <eemaan.amir@gmail.com>
2024-02-07 15:56:27 +05:00
sundasnoreen12
5f43f945bb Merge pull request #989 from openedx/sundas/INF-1243
test: added test cases to change toggle based on channel
2024-02-07 14:45:46 +05:00
Ahtisham Shahid
0ee0f41f3e Merge pull request #988 from openedx/ahtisham/INF-1242
feat: added notification title for contentReported
2024-02-06 14:13:06 +05:00
renovate[bot]
35b66ae38b fix(deps): update react-router monorepo to v6.22.0 2024-02-05 13:10:30 +00:00
renovate[bot]
361e14c980 fix(deps): update dependency @edx/frontend-platform to v7.1.0 2024-02-05 07:54:43 +00:00
Omar Al-Ithawi
8e967fa3bf feat: tutor-mfe compatiblilty for atlas pull (#987)
- install atlas
 - remove `--filter` to pull all languages by default
 - use ATLAS_OPTIONS to allow custom `--filter`
 - include frontend-platform in `atlas pull`

Refs: FC-0012 OEP-58
2024-02-02 09:33:00 -05:00
sundasnoreen12
67feee5e0b refactor: fix reveiw issues 2024-02-01 19:43:27 +05:00
sundasnoreen12
837ac4e635 test: added test cases to change toggle based on channel 2024-02-01 16:47:02 +05:00
Ahtisham Shahid
5c6ddd2888 feat: added notification title for contentReported 2024-01-31 13:18:10 +05:00
Brian Smith
7ef1b5b92d chore(deps): update paragon and frontend-build to openedx scope (#982) 2024-01-29 10:52:37 -05:00
edX requirements bot
672d39f99c chore: update browserslist DB (#978)
Co-authored-by: abdullahwaheed <abdullahwaheed@users.noreply.github.com>
2024-01-23 15:20:54 +05:00
edx-transifex-bot
08a0d8e30b chore(i18n): update translations (#977)
Co-authored-by: Jenkins <sre+jenkins@edx.org>
2024-01-23 15:00:21 +05:00
renovate[bot]
208c7a1ada fix(deps): update react-router monorepo to v6.21.3 2024-01-22 07:57:21 +00:00
renovate[bot]
afe2a754bd fix(deps): update dependency core-js to v3.35.1 2024-01-22 07:56:21 +00:00
Attiya Ishaque
594ffe4aa9 Merge pull request #971 from openedx/attiya/VAN-1790
feat: add  work experience field
2024-01-19 18:44:25 +05:00
attiyaishaque
8ecdedcdc8 feat: add work experience field 2024-01-19 16:03:17 +05:00
renovate[bot]
11e144dec0 fix(deps): update react-router monorepo to v6.21.2 2024-01-15 07:21:47 +00:00
renovate[bot]
c71e586e64 fix(deps): update dependency redux-saga to v1.3.0 2024-01-15 07:21:36 +00:00
renovate[bot]
d0d2aeed71 fix(deps): update dependency core-js to v3.35.0 2024-01-15 07:20:55 +00:00
renovate[bot]
737833cdeb fix(deps): update dependency classnames to v2.5.1 2024-01-15 05:13:19 +00:00
Bilal Qamar
c00ebc9f64 chore: bumped frontend-platform to v6 (#950)
* chore: bumped frontend-platform to v6

* refactor: updated snapshots

* refactor: updated package-lock

* refactor: bumped frontend-platform version

* refactor: updated package-lock and snapshots

* refactor: updated package-lock
2024-01-11 18:36:13 +05:00
dependabot[bot]
41ee7e9538 chore(deps): bump follow-redirects from 1.15.2 to 1.15.4 (#972)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.2 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.2...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-11 14:01:51 +05:00
renovate[bot]
b7181d5643 fix(deps): update dependency @edx/frontend-component-footer to v12.7.1 2024-01-08 14:39:38 +00:00
renovate[bot]
50e0235a6a fix(deps): update dependency @edx/frontend-component-header to v4.11.1 2024-01-08 06:21:27 +00:00
Dmytro
5166546048 fix: Fixed the display of the selection of available time zones (#896) 2024-01-01 23:07:56 +05:00
renovate[bot]
49d3acd1a1 fix(deps): update dependency @edx/frontend-component-header to v4.11.0 2024-01-01 09:06:06 +00:00
renovate[bot]
cdf799d515 fix(deps): update dependency @edx/frontend-component-footer to v12.7.0 2024-01-01 07:29:31 +00:00
Syed Ali Abbas Zaidi
ed26467f0d feat: migrate enzyme with RTL (#945) 2023-12-26 13:22:06 +05:00
edx-transifex-bot
fea3991915 chore(i18n): update translations (#962)
Co-authored-by: Jenkins <sre+jenkins@edx.org>
2023-12-26 11:37:24 +05:00
renovate[bot]
30ca5f577e fix(deps): update dependency core-js to v3.34.0 2023-12-25 06:51:49 +00:00
renovate[bot]
4047c3c923 fix(deps): update dependency @edx/frontend-component-footer to v12.6.2 2023-12-25 06:51:26 +00:00
renovate[bot]
3d32c8624d fix(deps): update dependency regenerator-runtime to v0.14.1 2023-12-18 07:00:42 +00:00
renovate[bot]
0c70e31655 chore(deps): update dependency @edx/frontend-build to v13.0.14 2023-12-18 07:00:13 +00:00
renovate[bot]
10e1a451f7 fix(deps): update dependency @edx/frontend-component-footer to v12.6.1 2023-12-11 07:34:44 +00:00
renovate[bot]
7f2d3700d7 chore(deps): update dependency @edx/frontend-build to v13.0.12 2023-12-11 07:34:26 +00:00
dependabot[bot]
eb88d9b46d chore(deps-dev): bump @adobe/css-tools from 4.2.0 to 4.3.2 (#951)
Bumps [@adobe/css-tools](https://github.com/adobe/css-tools) from 4.2.0 to 4.3.2.
- [Changelog](https://github.com/adobe/css-tools/blob/main/History.md)
- [Commits](https://github.com/adobe/css-tools/commits)

---
updated-dependencies:
- dependency-name: "@adobe/css-tools"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-08 15:00:28 +05:00
sundasnoreen12
26dbac709f Merge pull request #954 from openedx/sundas/INF-1036
fix: disable app level toggle during api call
2023-12-07 14:18:39 +05:00
sundasnoreen12
d6592a77f9 fix: disable app level toggle during api call 2023-12-06 15:23:06 +05:00
renovate[bot]
91d0feaed9 chore(deps): update actions/checkout action to v4 (#953)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-06 13:15:40 +05:00
renovate[bot]
237599c830 fix(deps): update react-router monorepo to v6.20.1 2023-12-04 07:10:49 +00:00
sundasnoreen12
56d0ad3db9 Merge pull request #947 from openedx/sundas/INF-1164
fix: app level toggle is now disabled during api call
2023-11-30 13:20:52 +05:00
sundasnoreen12
c0b504763e fix: app level toggle is now disabled during api call 2023-11-29 22:57:04 +05:00
renovate[bot]
4aa44b89a3 fix(deps): update react-router monorepo to v6.20.0 2023-11-29 13:36:02 +00:00
renovate[bot]
be661b8a27 fix(deps): update dependency @edx/frontend-component-header to v4.10.1 2023-11-27 10:35:20 +00:00
renovate[bot]
3c75052d8b fix(deps): update dependency @edx/frontend-component-footer to v12.6.0 2023-11-27 07:27:16 +00:00
renovate[bot]
229a674469 chore(deps): update dependency @edx/frontend-build to v13.0.8 2023-11-20 11:05:36 +00:00
edx-transifex-bot
2c75c7f790 chore(i18n): update translations (#938)
Co-authored-by: Jenkins <sre+jenkins@edx.org>
2023-11-20 13:08:36 +05:00
renovate[bot]
d595986d0e fix(deps): update dependency core-js to v3.33.3 2023-11-20 08:06:20 +00:00
Mashal Malik
43d8784014 refactor: updated README file to reflect template changes (#893)
* refactor: updated README file to reflect template changes

* refactor: updated README file to reflect template changes

* refactor: updated README file to reflect template changes

* refactor: updated README file to reflect template changes
2023-11-14 12:57:40 +05:00
renovate[bot]
f15b71d20c chore(deps): update dependency @edx/frontend-build to v13.0.5 2023-11-13 07:23:24 +00:00
renovate[bot]
aae79c45bb fix(deps): update dependency core-js to v3.33.2 2023-11-13 07:21:25 +00:00
dependabot[bot]
5233c6aa59 chore(deps): bump @babel/traverse from 7.22.5 to 7.23.2 (#914)
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.22.5 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-08 17:56:54 +05:00
renovate[bot]
d59c9e38bd chore(deps): update dependency @edx/frontend-build to v13.0.4 2023-11-06 07:42:20 +00:00
renovate[bot]
eb35897bf7 fix(deps): update dependency @edx/frontend-component-footer to v12.5.1 2023-11-06 07:41:03 +00:00
Stanislav
c28b8c6840 fix: Add ID attribute to the main content (#880)
Co-authored-by: Stanislav Lunyachek <lunyachek@MacBook-Pro-M1.local>
2023-11-03 16:17:14 +05:00
Bilal Qamar
1698720aad Revert "refactor: bumped frontend-platform version to v6" (#932)
* Revert "refactor: bumped frontend-platform version to v6 (#910)"

This reverts commit 57a2c7bcb6.

* refactor: updated package-lock
2023-11-01 16:31:22 +05:00
Bilal Qamar
57a2c7bcb6 refactor: bumped frontend-platform version to v6 (#910)
* refactor: bumped frontend-platform version

* refactor: updated paragon and snapshots

* refactor: bumped edx packages

* refactor: bumped frontend-build version

* refactor: bumped frontend-platform version

* refactor: pinned paragon version
2023-10-31 16:58:41 +05:00
renovate[bot]
f6f67a1a80 fix(deps): update dependency @edx/frontend-platform to v5.6.1 2023-10-30 06:32:52 +00:00
renovate[bot]
aec7e1281f fix(deps): update dependency @edx/brand to v1.2.3 2023-10-30 06:31:47 +00:00
edx-transifex-bot
cdf0ee5e4e chore(i18n): update translations (#928)
Co-authored-by: Jenkins <sre+jenkins@edx.org>
2023-10-30 11:26:36 +05:00
Ihor Romaniuk
f0858b7381 fix: trim long text in links in the social networks block (#916) 2023-10-25 15:05:08 +05:00
Helder Sepulveda
5f49bedaa8 fix: Correction to the language code for Português, Italian and German (#903)
fix: Correction to the language code for Português, Italian and German

lowercase code for DE

lowercase code for IT

Co-authored-by: Omar Al-Ithawi <i@omardo.com>
2023-10-23 16:10:24 -04:00
Muhammad Abdullah Waheed
a94f472459 fix: fixed typo of other education which was breaking the response (#919)
* fix: fixed typo of other education which was breaking the response

* fix: fixed typo
2023-10-23 16:10:31 +05:00
renovate[bot]
2fc2d86a44 fix(deps): update dependency @edx/frontend-component-header to v4.8.0 2023-10-23 10:54:56 +00:00
renovate[bot]
899f88ca1e fix(deps): update dependency @edx/frontend-component-footer to v12.5.0 2023-10-23 06:25:12 +00:00
renovate[bot]
399dd04df6 chore(deps): update dependency @edx/frontend-build to v13.0.3 2023-10-23 04:49:09 +00:00
renovate[bot]
46dd8739ab fix(deps): update dependency core-js to v3.33.1 2023-10-23 04:47:14 +00:00
Feanil Patel
5de18e0dba chore: Update to the new version of brand-openedx in the new scope. (#918)
Part of https://github.com/openedx/axim-engineering/issues/23

This updates the brand alias to point to the package at the `openedx`
scope.  This does not impact imports because this package is used via an
alias.
2023-10-20 17:31:08 -04:00
sundasnoreen12
ca3bc9151c Merge pull request #913 from openedx/sundass/INF-1086
fix: removed extra loader while updating preferences
2023-10-19 17:35:56 +05:00
Awais Ansari
9cccf09394 Merge pull request #912 from openedx/aansari/code-refactoring
refactor: removed disable eslint and created channels constant
2023-10-18 16:26:59 +05:00
sundasnoreen12
ced29278d5 test: fixed test cases 2023-10-17 13:27:04 +05:00
sundasnoreen12
bc8197a9af fix: removed extra loader while updating preferences 2023-10-17 13:15:14 +05:00
Awais Ansari
f86677171f refactor: removed disable eslint and created channels constant 2023-10-16 19:49:35 +05:00
renovate[bot]
966b59b70f fix(deps): update dependency @edx/frontend-component-footer to v12.4.0 2023-10-16 07:35:09 +00:00
renovate[bot]
0e6aff7c6f fix(deps): update dependency @edx/frontend-platform to v5.5.4 2023-10-16 07:34:54 +00:00
renovate[bot]
13dbb732e3 fix(deps): update dependency @edx/paragon to v20.46.3 2023-10-16 06:41:16 +00:00
renovate[bot]
b80748aa4c fix(deps): update dependency @edx/frontend-component-header to v4.7.1 2023-10-16 06:39:23 +00:00
Muhammad Abdullah Waheed
f098fe1a3a feat: babel-plugin-react-intl to babel-plugin-formatjs migration (#894)
* feat: babel-plugin-react-intl to babel-plugin-formatjs migration

* fix: upgradfed frontend-build to fix security issue
2023-10-10 17:05:08 +05:00
edx-transifex-bot
a989fabb92 chore(i18n): update translations (#902)
Co-authored-by: Jenkins <sre+jenkins@edx.org>
2023-10-10 16:12:18 +05:00
sundasnoreen12
1257e81781 Merge pull request #901 from openedx/sundas/INF-1086
fix: fixed preferences toggle unpredictable behavior
2023-10-10 11:03:10 +05:00
renovate[bot]
b08890b794 fix(deps): update dependency @edx/frontend-component-header to v4.7.0 2023-10-09 09:33:28 +00:00
sundasnoreen12
7f1c7b86ef fix: fixed preferences toggle unpredictable behaviour 2023-10-09 11:52:58 +05:00
renovate[bot]
a5fd3a7f7e fix(deps): update dependency @edx/frontend-component-footer to v12.3.0 2023-10-09 06:15:44 +00:00
Deborah Kaplan
4513cc8834 feat: remove (long-disabled) coaching functionality (#891)
* Removes the coaching functionality
* no tests are referencing this
* Leaves behind a decision record referencing the creation of the
  coaching functionality (0002-coaching-addition)

FIXES: APER-2408-Remove-Coaching-functionality-from-the-Account-MFE
2023-10-04 18:36:09 +05:00
Mashal Malik
40103a2386 refactor: add @openedx in renovate automate configuration (#886) 2023-10-02 16:39:21 +05:00
edx-transifex-bot
b6c18bb439 chore(i18n): update translations (#888)
Co-authored-by: Jenkins <sre+jenkins@edx.org>
2023-10-02 11:32:15 +05:00
renovate[bot]
ee51939f2d fix(deps): update dependency core-js to v3.33.0 2023-10-02 02:28:08 -04:00
renovate[bot]
fc127ccd98 chore(deps): update dependency @edx/frontend-build to v12.9.17 2023-10-02 02:27:36 -04:00
edx-transifex-bot
22faebac50 chore(i18n): update translations (#872)
Co-authored-by: Jenkins <sre+jenkins@edx.org>
2023-10-02 11:27:02 +05:00
renovate[bot]
5ce3995f5b fix(deps): update dependency regenerator-runtime to v0.14.0 2023-09-25 03:59:00 -04:00
renovate[bot]
e181269703 fix(deps): update dependency @edx/frontend-component-header to v4.6.1 2023-09-25 03:58:25 -04:00
renovate[bot]
5d212ec6b5 fix(deps): update dependency @edx/frontend-platform to v5.4.0 2023-09-25 04:21:30 +00:00
renovate[bot]
363096c4f0 fix(deps): update dependency form-urlencoded to v6.1.4 2023-09-25 00:21:09 -04:00
Dmytro
85c5902559 feat: add toggling for the hardcode support link (for master) (#864)
* feat: add toggling for the hardcode support link (master)

Add a toggling mechanism for the "unlink all social media
accounts" text to show it as a link or text depending on
the MFE env setting.

* fix(deps): update dependency @edx/frontend-platform to v5.3.0

* Revert "fix(deps): update dependency @edx/frontend-platform to v5.3.0" (#870)

This reverts commit 757e446be7.

* feat: add toggling for the hardcode support link (master)

Add a toggling mechanism for the "unlink all social media
accounts" text to show it as a link or text depending on
the MFE env setting.

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Muhammad Abdullah Waheed <42172960+abdullahwaheed@users.noreply.github.com>
2023-09-21 13:28:45 +05:00
edx-transifex-bot
fca6da2df7 chore(i18n): update translations (#877)
Co-authored-by: Jenkins <sre+jenkins@edx.org>
2023-09-19 11:18:14 +05:00
sundasnoreen12
7a74e5d29b Merge pull request #876 from openedx/sundas/INF-1061
fix: removed underline from course name
2023-09-18 13:53:44 +05:00
renovate[bot]
4b94344dd9 fix(deps): update dependency core-js to v3.32.2 2023-09-18 02:04:27 -04:00
renovate[bot]
5245254de5 fix(deps): update dependency form-urlencoded to v6.1.3 2023-09-18 02:04:07 -04:00
SundasNoreen
afda76ff11 fix: removed underline from course name 2023-09-12 16:56:49 +05:00
Muhammad Abdullah Waheed
da52ddd35a fix: bumped frontend-platform to latest version to fix ci issues (#875) 2023-09-11 19:25:24 +05:00
renovate[bot]
bb2aef3878 fix(deps): update dependency @edx/frontend-platform to v5.3.1 2023-09-11 02:38:15 -04:00
renovate[bot]
4d6f76d9b3 fix(deps): update dependency form-urlencoded to v6.1.2 2023-09-11 02:37:54 -04:00
Awais Ansari
869e083a2a Merge pull request #869 from openedx/sundas/INF-1016
feat: Added link to documentation on preferences UI
2023-09-06 16:36:35 +05:00
SundasNoreen
ee876b5c84 refactor: added paragon class 2023-09-05 23:11:27 +05:00
Muhammad Abdullah Waheed
a2b25449de Revert "fix(deps): update dependency @edx/frontend-platform to v5.3.0" (#870)
This reverts commit 757e446be7.
2023-09-05 20:24:23 +05:00
SundasNoreen
16218252f1 feat: Added link to documentation on preferences UI 2023-09-05 13:39:46 +05:00
renovate[bot]
757e446be7 fix(deps): update dependency @edx/frontend-platform to v5.3.0 2023-09-04 03:06:25 -04:00
Mashal Malik
db0f8f80bc refactor: update lock file version (#855) 2023-08-31 12:43:54 +05:00
Jonas Burigo Martins
49bc817f2d feat: Allow disable account deletion (#817)
* feat: allow disable account deletion

* test: add disable account deletion to test case

* style: fix lint errors

* docs: Add ENABLE_ACCOUNT_DELETION to README.rst
2023-08-28 15:40:48 +05:00
Bilal Qamar
c31beeef96 Revert "fix(deps): update dependency @tensorflow-models/blazeface to v0.1.0" (#861)
This reverts commit 09970d7935.
2023-08-28 14:33:52 +05:00
renovate[bot]
09970d7935 fix(deps): update dependency @tensorflow-models/blazeface to v0.1.0 2023-08-28 06:25:25 +00:00
renovate[bot]
d15b0baf74 fix(deps): update dependency @edx/frontend-component-footer to v12.2.1 2023-08-28 06:25:03 +00:00
edx-transifex-bot
b9802a130e chore(i18n): update translations (#856)
Co-authored-by: Jenkins <sre+jenkins@edx.org>
2023-08-28 11:20:41 +05:00
Syed Ali Abbas Zaidi
7c0ea75e21 refactor: remove history pacakge (#853)
* refactor: remove history pacakge

* chore: improve test coverage
2023-08-23 18:21:29 +05:00
edX requirements bot
e1b02de7de chore: update browserslist DB (#850)
Co-authored-by: abdullahwaheed <abdullahwaheed@users.noreply.github.com>
2023-08-23 15:52:19 +05:00
Muhammad Adeel Tajamul
6c4dbc5db0 fix: changed overlay position and updated notification info text (#849) 2023-08-22 10:46:14 +05:00
Awais Ansari
d180626122 Merge pull request #848 from openedx/aansari/INF-1018
fix: moved feedback widget behind env variable
2023-08-21 14:49:29 +05:00
renovate[bot]
a9518b7388 fix(deps): update dependency @edx/frontend-platform to v5.1.0 2023-08-21 05:17:34 +00:00
renovate[bot]
51b18e9c52 chore(deps): update dependency @edx/frontend-build to v12.9.10 2023-08-21 05:17:18 +00:00
Syed Ali Abbas Zaidi
3d98558bf6 feat: upgrade react rotuer to v6 (#793)
* feat: upgrade react rotuer to v6

* fix: test cases

* build: update header and footer

* refactor: update jumpnav test case
2023-08-18 12:29:07 +05:00
edX requirements bot
e7e7f518bf chore: update browserslist DB (#840)
Co-authored-by: abdullahwaheed <abdullahwaheed@users.noreply.github.com>
2023-08-17 11:38:51 +05:00
Awais Ansari
cb06c8778a fix: notification courses failed test cases 2023-08-16 17:42:32 +05:00
Awais Ansari
ab5c205a7f fix: moved feedback widget behind env variable 2023-08-15 19:00:29 +05:00
edx-transifex-bot
2f85902d2c chore(i18n): update translations (#843)
Co-authored-by: Jenkins <sre+jenkins@edx.org>
2023-08-15 17:43:34 +05:00
renovate[bot]
b75e78bdda fix(deps): update dependency @edx/frontend-platform to v4.6.1 2023-08-14 14:01:36 +00:00
renovate[bot]
182a0251a4 fix(deps): update dependency @edx/paragon to v20.46.2 2023-08-14 02:14:20 -04:00
renovate[bot]
89881c64a6 fix(deps): update dependency @edx/frontend-component-header to v4.5.0 2023-08-14 02:13:51 -04:00
renovate[bot]
7321e2a159 chore(deps): update dependency @edx/frontend-build to v12.9.4 2023-08-14 00:22:28 -04:00
Awais Ansari
9b45aa3bc9 Merge pull request #842 from openedx/aansari/INF-990
style: change feedback widget location
2023-08-08 13:59:57 +05:00
Awais Ansari
dfadac08d3 style: change feedback widget location 2023-08-08 13:46:02 +05:00
Awais Ansari
2e87f0bd9f Merge pull request #839 from openedx/aansari/INF-990
feat: remove other channels then web preferences
2023-08-08 13:02:49 +05:00
Awais Ansari
7f8086545c test: define lightningjs in window object 2023-08-07 15:00:05 +05:00
Awais Ansari
de6e3c2010 feat: add feedback widget for notification preferences 2023-08-04 15:54:11 +05:00
edX requirements bot
eb6d0125c6 chore: update browserslist DB (#790)
Co-authored-by: abdullahwaheed <abdullahwaheed@users.noreply.github.com>
2023-08-04 15:52:16 +05:00
Awais Ansari
e8f754c10b style: update the notification preferences page style according to figma 2023-08-03 18:01:13 +05:00
Awais Ansari
a72bbf2f58 feat: remove other channels then web preferences 2023-08-03 16:15:47 +05:00
renovate[bot]
c465f51e66 chore(deps): update dependency @testing-library/jest-dom to v5.17.0 2023-07-31 00:24:18 -04:00
renovate[bot]
599e658742 chore(deps): update dependency @edx/frontend-build to v12.9.3 2023-07-31 00:24:02 -04:00
Omar Al-Ithawi
929a669cad feat: include paragon in atlas pull (#833)
This pull request is part of the [FC-0012 project](https://openedx.atlassian.net/l/cp/XGS0iCcQ) which is sparked by the [Translation Infrastructure update OEP-58](https://open-edx-proposals.readthedocs.io/en/latest/architectural-decisions/oep-0058-arch-translations-management.html#specification).
2023-07-25 18:23:08 +05:00
renovate[bot]
503b8b5176 chore(deps): update dependency @edx/frontend-build to v12.9.2 2023-07-24 07:57:00 +00:00
renovate[bot]
d2aa727c12 fix(deps): update dependency @edx/frontend-component-header to v4.4.4 2023-07-24 03:51:58 -04:00
Bilal Qamar
d66dcecd2f feat: update react & react-dom to v17 (#803)
* feat: update react & react-dom to v17

* feat: update react & react-dom to v17

* build: update lock file

* refactor: updated edx packages

* refactor: removed unnecessary lint disable

---------

Co-authored-by: mashal-m <mashal.malik@arbisoft.com>
2023-07-18 12:28:32 +05:00
edx-transifex-bot
80d0c44b40 chore(i18n): update translations (#829)
Co-authored-by: Jenkins <sre+jenkins@edx.org>
2023-07-17 17:53:27 +05:00
dependabot[bot]
0e5cd30d01 chore(deps): bump tough-cookie from 4.1.2 to 4.1.3 (#820)
Bumps [tough-cookie](https://github.com/salesforce/tough-cookie) from 4.1.2 to 4.1.3.
- [Release notes](https://github.com/salesforce/tough-cookie/releases)
- [Changelog](https://github.com/salesforce/tough-cookie/blob/master/CHANGELOG.md)
- [Commits](https://github.com/salesforce/tough-cookie/compare/v4.1.2...v4.1.3)

---
updated-dependencies:
- dependency-name: tough-cookie
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-17 10:49:01 +05:00
renovate[bot]
56b9fe3998 fix(deps): update dependency @edx/frontend-component-footer to v12.1.2 2023-07-17 01:08:58 -04:00
renovate[bot]
a22f1298eb chore(deps): update dependency @edx/frontend-build to v12.8.65 2023-07-17 05:08:34 +00:00
dependabot[bot]
b7bd6a2846 chore(deps): bump semver from 5.7.1 to 5.7.2 (#827)
Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-17 10:07:10 +05:00
Awais Ansari
a52ab171de Merge pull request #828 from openedx/aansari/INF-952
feat: implement showPreferences flag in notification preferences
2023-07-14 12:54:34 +05:00
Awais Ansari
13a7508f26 test: fix JumpNav test cases 2023-07-13 15:51:45 +05:00
Awais Ansari
a499aa4cc5 feat: implement showPreferences flag in notification preferences 2023-07-13 14:01:03 +05:00
Awais Ansari
e7207878d4 Merge pull request #825 from openedx/aansari/INF-948
refactor: update notEditable to nonEditable in notification preferences
2023-07-11 12:21:24 +05:00
Awais Ansari
47d64c1cf5 refactor: update notEditable to nonEditable in notification preferences 2023-07-10 18:12:11 +05:00
renovate[bot]
c75dc86263 fix(deps): update dependency @edx/frontend-component-header to v4.4.0 2023-07-10 05:01:18 -04:00
Mashal Malik
105a8d1a3c chore: add paragon messages (#818)
* fix(deps): update dependency @edx/paragon to v20.44.0

* chore: add paragon messages

* build: update lock file

* build: update lock file

* build: update lock file

* build: update lock file

* build: update lock file

* build: update lock file

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-10 13:59:46 +05:00
renovate[bot]
c74cf52e38 fix(deps): update dependency @edx/frontend-component-footer to v12.1.1 2023-07-10 02:43:35 -04:00
renovate[bot]
5c9b448b14 fix(deps): update dependency core-js to v3.31.1 2023-07-10 00:10:06 -04:00
renovate[bot]
4e95495dcc chore(deps): update dependency @edx/frontend-build to v12.8.60 2023-07-10 00:09:47 -04:00
renovate[bot]
82f86f5fbe fix(deps): update dependency @edx/frontend-component-header to v4.2.3 2023-07-03 10:56:56 +00:00
Awais Ansari
f737d6e158 Merge pull request #814 from openedx/aansari/INF-914
feat: load more courses button in notification courses list
2023-07-03 13:53:09 +05:00
renovate[bot]
f9feb94668 chore(deps): update dependency @edx/frontend-build to v12.8.57 2023-07-03 08:34:25 +00:00
Awais Ansari
112afa7e51 test: add load more courses test case 2023-06-26 19:34:05 +05:00
Awais Ansari
1694ea38ab feat: load more courses button in notification courses list 2023-06-26 18:46:06 +05:00
renovate[bot]
0f3b7caa0f fix(deps): update dependency reselect to v4.1.8 2023-06-19 21:29:42 +00:00
renovate[bot]
a85e1e1e15 fix(deps): update dependency redux-thunk to v2.4.2 2023-06-19 18:42:13 +00:00
renovate[bot]
55d00027a9 fix(deps): update dependency @edx/frontend-component-header to v4.1.0 2023-06-19 12:25:45 +00:00
renovate[bot]
bf012619a6 chore(deps): update dependency @edx/frontend-build to v12.8.54 2023-06-19 06:33:44 +00:00
renovate[bot]
f47795bf40 fix(deps): update dependency @edx/paragon to v20.44.0 (#806)
* fix(deps): update dependency @edx/paragon to v20.44.0

* fix: update snapshots

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: mashal-m <mashal.malik@arbisoft.com>
2023-06-13 19:50:46 +05:00
renovate[bot]
848e7a2f85 fix(deps): update dependency redux-saga to v1.2.3 2023-06-12 14:12:51 +00:00
renovate[bot]
ecc6138833 fix(deps): update dependency core-js to v3.31.0 2023-06-12 11:30:46 +00:00
Muhammad Adeel Tajamul
d6600eb876 test: added tests for notification preferences (#802) 2023-06-12 13:00:52 +05:00
renovate[bot]
bc237de755 chore(deps): update dependency @edx/frontend-build to v12.8.51 2023-06-12 07:38:35 +00:00
Jenkins
89abb51734 chore(i18n): update translations 2023-06-11 17:03:54 -04:00
Muhammad Adeel Tajamul
be8570edac feat: integrate notification preferences api (#794) 2023-06-06 11:04:23 +05:00
renovate[bot]
09cce6802d fix(deps): update dependency @edx/frontend-platform to v4.5.1 2023-06-05 17:17:50 +00:00
renovate[bot]
c164dd7dcf chore(deps): update dependency @edx/frontend-build to v12.8.40 2023-06-05 12:29:18 +00:00
renovate[bot]
00435fb27d fix(deps): update dependency @edx/frontend-platform to v4.5.0 2023-05-29 09:00:15 +00:00
renovate[bot]
0ebaa0b991 chore(deps): update dependency @edx/frontend-build to v12.8.38 2023-05-29 07:54:53 +00:00
Jenkins
0d7b529233 chore(i18n): update translations 2023-05-28 17:03:50 -04:00
renovate[bot]
2c2f7e8e98 fix(deps): update dependency qs to v6.11.2 2023-05-22 12:54:19 +00:00
renovate[bot]
768b8a2417 fix(deps): update dependency @edx/frontend-component-header to v4.0.3 2023-05-22 08:40:26 +00:00
Muhammad Adeel Tajamul
192714629c feat: added notification preference ui (#784) 2023-05-22 06:17:51 +05:00
edX requirements bot
f2f761e8db chore: update browserslist DB (#787)
Co-authored-by: abdullahwaheed <abdullahwaheed@users.noreply.github.com>
2023-05-18 18:37:57 +05:00
renovate[bot]
410aa14b28 fix(deps): update dependency core-js to v3.30.2 2023-05-15 14:10:07 +00:00
renovate[bot]
e857293414 fix(deps): update dependency @edx/paragon to v20.36.0 2023-05-15 10:49:43 +00:00
edX requirements bot
492f911930 chore: update browserslist DB (#775)
Co-authored-by: abdullahwaheed <abdullahwaheed@users.noreply.github.com>
2023-05-11 14:10:36 +05:00
renovate[bot]
0002d84a6c fix(deps): update dependency @edx/frontend-component-header to v4.0.2 2023-05-08 17:20:01 +00:00
renovate[bot]
9b49b38496 chore(deps): update dependency @edx/frontend-build to v12.8.27 2023-05-08 08:37:54 +00:00
renovate[bot]
7cf9294e09 chore(deps): update dependency @edx/browserslist-config to v1.2.0 2023-05-01 12:58:51 +00:00
renovate[bot]
129f73aa4f chore(deps): update dependency @edx/frontend-build to v12.8.16 2023-05-01 08:20:20 +00:00
Adolfo R. Brandes
7bdb93784b Merge pull request #779 from raccoongang/sagirov/tCRIL_GA-58
[FC-0014] update frontend-platform version to v4.2.0
2023-04-26 19:19:15 -03:00
Sagirov Eugeniy
b32c001fec chore: update frontend-platform version to v4.2.0 2023-04-21 14:21:48 +03:00
Omar Al-Ithawi
5f134d7b99 feat: use atlas in make pull_translations (#774)
Changes:
 - Bump frontend-platform to bring intl-imports.js script
 - Move all i18n imports into `src/i18n/index.js` so intl-imports.js can
   override it with latest translations
 - Add `atlas` into `make pull_translations` when `OPENEDX_ATLAS_PULL`
   environment variable is set.
 - Fixed lint rules for frontend-platform@4.1.0

Refs: [FC-0012 project](https://openedx.atlassian.net/l/cp/XGS0iCcQ) implementing Translation Infrastructure OEP-58.
2023-04-20 12:26:47 -04:00
Bilal Qamar
81b0823632 refactor: reverted platform to v2.6 to avoid dependency issues (#778) 2023-04-20 10:52:46 +05:00
renovate[bot]
95e3af7487 chore(deps): update dependency @edx/frontend-build to v12.8.10 (#776)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-17 14:13:28 +05:00
renovate[bot]
77047bab2a fix(deps): update dependency long to v5.2.3 (#777)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-17 14:12:55 +05:00
Jenkins
c1cf6d65de chore(i18n): update translations 2023-04-13 08:44:36 -04:00
renovate[bot]
f626fc2f89 fix(deps): update dependency @edx/frontend-component-footer to v11.7.2 2023-04-11 21:35:12 +00:00
renovate[bot]
f56b1b4530 fix(deps): update dependency @edx/frontend-component-header to v3.7.2 2023-04-11 05:33:19 +00:00
Bilal Qamar
1c423c4b6c feat: upgraded to node v18, added .nvmrc and updated workflows (#759)
* feat: upgraded to node v18, added .nvmrc and updated workflows

* refactor: updated workflow

* refactor: upgraded frontend-platform to v4

* build: updated frontend-build, frontend-platform, component-footer & component-header packages
2023-04-10 12:55:48 +05:00
edX requirements bot
7715b143d2 chore: update browserslist DB (#764)
Co-authored-by: abdullahwaheed <abdullahwaheed@users.noreply.github.com>
2023-04-10 11:03:12 +05:00
renovate[bot]
b200417903 fix(deps): update dependency @edx/frontend-component-header to v3.7.0 2023-04-03 12:43:34 +00:00
renovate[bot]
138d80d57d fix(deps): update dependency @edx/frontend-component-footer to v11.7.0 2023-04-03 10:44:28 +00:00
renovate[bot]
07a33447ad chore(deps): update dependency @edx/frontend-build to v12.7.0 2023-03-27 19:56:09 +00:00
renovate[bot]
4d11d28f96 fix(deps): update dependency @edx/frontend-component-header to v3.6.5 2023-03-27 12:09:12 +00:00
renovate[bot]
e61dc12eab chore(deps): update dependency @edx/frontend-build to v12.6.2 2023-03-24 10:46:08 +00:00
edX requirements bot
2c268d906c chore: update browserslist DB (#756)
Co-authored-by: abdullahwaheed <abdullahwaheed@users.noreply.github.com>
2023-03-22 17:23:44 +05:00
renovate[bot]
0acaebe067 fix(deps): update dependency qs to v6.11.1 2023-03-20 10:36:09 +00:00
renovate[bot]
9ea109f705 fix(deps): update dependency @edx/paragon to v20.28.5 2023-03-20 07:13:38 +00:00
Jenkins
be2964562f chore(i18n): update translations 2023-03-19 17:03:40 -04:00
Yoiber
6d7bf1b878 chore(i18n): add more languages (#747)
* chore(i18n): add more languages

* chore(i18n): Pylint fixes
2023-03-09 18:45:20 +05:00
renovate[bot]
3a7c963f3c fix(deps): update dependency @edx/paragon to v20.28.4 2023-03-07 01:06:59 +00:00
renovate[bot]
3728928a6d fix(deps): update dependency @edx/frontend-component-header to v3.6.4 2023-03-06 12:45:10 +00:00
Mashal Malik
596eeee59d refactor: remove unused tranisfex v2 url (#755) 2023-03-03 17:51:17 +05:00
Eugene Dyudyunov
ae2f8a384f feat: make password reset support URL configurable (#745)
* feat: make password reset support URL configurable

Replace the hardcoded `support.edx.org` value with the one from the env vars.

* fix: linting error
2023-03-02 11:46:32 +05:00
Sarina Canelake
ffe0989969 Merge pull request #750 from openedx/update-readme
docs: Remove old maintaining team from README
2023-02-28 09:56:10 -05:00
renovate[bot]
53eeb26e28 fix(deps): update dependency redux to v4.2.1 2023-02-27 16:05:10 +00:00
Feanil Patel
0325d2a7f6 Update standard workflow files. (#751)
* 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.

* 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.

* 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-27 13:46:43 +05:00
edX requirements bot
b83d568dfb chore: update browserslist DB (#752)
Co-authored-by: abdullahwaheed <abdullahwaheed@users.noreply.github.com>
2023-02-27 11:35:54 +05:00
edX requirements bot
2f839b3362 chore: update browserslist DB (#744)
Co-authored-by: abdullahwaheed <abdullahwaheed@users.noreply.github.com>
2023-02-24 13:30:19 -08:00
Sarina Canelake
bfc655d6ab docs: Remove old maintaining team from README 2023-02-22 18:35:02 -05:00
renovate[bot]
bd63ea9484 fix(deps): update dependency @edx/frontend-component-header to v3.6.3 2023-02-20 19:04:27 +00:00
renovate[bot]
6c825625fb fix(deps): update dependency @edx/frontend-component-footer to v11.6.3 2023-02-20 13:02:24 +00:00
Jenkins
be59c2da90 chore(i18n): update translations 2023-02-12 16:03:37 -05:00
edX requirements bot
8a4e6730a8 chore: update browserslist DB (#741)
Co-authored-by: abdullahwaheed <abdullahwaheed@users.noreply.github.com>
2023-02-07 18:47:58 +05:00
Jenkins
6053475c6f chore(i18n): update translations 2023-02-05 16:03:36 -05:00
edX requirements bot
ed1cfc28aa chore: update browserslist DB (#728)
Co-authored-by: abdullahwaheed <abdullahwaheed@users.noreply.github.com>
2023-02-01 14:29:59 +05:00
dependabot[bot]
1637aea0fa chore(deps): bump cookiejar from 2.1.3 to 2.1.4 (#737)
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-01 14:15:38 +05:00
Emad Rad
3c5aa05b48 Feature: Persian language Support (#666) 2023-02-01 11:36:29 +05:00
renovate[bot]
5a1dc5a992 fix(deps): update dependency form-urlencoded to v6 (#478)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-31 14:27:54 +05:00
dependabot[bot]
ccbf8201a0 chore(deps): bump json5 from 1.0.1 to 1.0.2 (#727)
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-01-31 14:12:51 +05:00
Jenkins
34be9f681a chore(i18n): update translations 2023-01-29 16:03:37 -05:00
Bilal Qamar
cfca229500 chore: update dependency @edx/frontend-build to v12.4.19 (#738) 2023-01-26 11:50:43 +05:00
renovate[bot]
d2396a8162 fix(deps): update dependency @edx/frontend-component-footer to v11.6.1 2023-01-23 13:52:01 +00:00
renovate[bot]
b630514906 chore(deps): update dependency @edx/frontend-build to v12.4.16 2023-01-23 09:53:56 +00:00
Jenkins
f8dbbf7757 chore(i18n): update translations 2023-01-22 16:08:39 -05:00
renovate[bot]
8eb26db72d fix(deps): update dependency redux to v4.2.0 2023-01-16 14:06:10 +00:00
renovate[bot]
499cbeaa62 fix(deps): update dependency @edx/paragon to v20.27.0 2023-01-16 09:11:35 +00:00
renovate[bot]
4b103161b9 fix(deps): update dependency qs to v6.11.0 2023-01-09 14:37:08 +00:00
renovate[bot]
fb8e4829c3 fix(deps): update dependency @edx/paragon to v20.26.3 2023-01-09 10:31:51 +00:00
renovate[bot]
4a81220aa3 fix(deps): update dependency @edx/brand to v1.2.0 2023-01-09 07:56:11 +00:00
renovate[bot]
85a0d751c0 fix(deps): update dependency prop-types to v15.8.1 2023-01-02 12:32:44 +00:00
renovate[bot]
859195be94 fix(deps): update dependency core-js to v3.27.1 2023-01-02 09:25:12 +00:00
renovate[bot]
8499002072 fix(deps): update dependency @edx/paragon to v20.25.0 2022-12-26 11:13:49 +00:00
renovate[bot]
6e85a2e1d9 fix(deps): update dependency @edx/frontend-component-header to v3.6.0 2022-12-26 08:37:21 +00:00
Jenkins
e4b4197a9a chore(i18n): update translations 2022-12-25 16:08:48 -05:00
renovate[bot]
60f34bf2ae chore(deps): update dependency @edx/frontend-build to v12.4.15 2022-12-22 00:44:44 +00:00
Muhammad Abdullah Waheed
63afc7d7be chore: auto update browserslist shared workflow (#720)
* chore: used a shared script to update broswerslist DB

* refactor: added required secrets param
2022-12-20 17:36:37 +05:00
renovate[bot]
0aec952fd2 fix(deps): update dependency @edx/frontend-component-footer to v11.6.0 2022-12-19 12:52:40 +00:00
renovate[bot]
f8b8374058 fix(deps): update dependency @edx/paragon to v20.21.5 2022-12-19 09:47:00 +00:00
Shahroz Ahmad
d62bb11a9e fix: added language codes to support affected languages (#708)
* fix: added language codes to support affected languages

* fix: temporary fix to unbreak Banner component on unexpected languages
2022-12-15 15:45:36 +05:00
renovate[bot]
af39ecbc5f fix(deps): update dependency @edx/paragon to v20.21.2 2022-12-12 09:24:49 +00:00
Jenkins
6c2330fc6c chore(i18n): update translations 2022-12-11 16:03:30 -05:00
Bilal Qamar
109da5fa38 feat: updated paragon & frontend-build version (#696)
* refactor: updated frontend-build version

* feat: updated paragon to v20

* refactor: updated snapshots
2022-12-09 14:56:55 +05:00
renovate[bot]
81ac063cf8 fix(deps): update dependency @edx/frontend-component-header to v3.5.0 2022-12-05 13:18:08 +00:00
renovate[bot]
50f2442512 fix(deps): update dependency @edx/frontend-component-footer to v11.5.2 2022-12-05 09:46:55 +00:00
Jenkins
be28f398d6 chore(i18n): update translations 2022-12-04 16:03:31 -05:00
alangsto
cd47862c1d Merge pull request #702 from openedx/alangsto/remove_dob_defaults
fix: prevent users from submitting DOB without update
2022-12-02 15:02:05 -05:00
Alie Langston
847e3e05b0 fix: prevent users from submitting DOB without update 2022-12-02 14:51:23 -05:00
Mashal Malik
e347b3fb23 refactor: migrate off modal paragon depreciation components (#654)
* refactor:  worked on modal paragon depreciation component and changed them into latest paragon modals

* refactor:  migrate off  modal paragon depreciation components

* fix: fix eslint and commit message

* fix: units tests were not working, its fixed

* test: add unit tests in modal

* test: add unit tests in id verfication modal

* refactor: convert test cases from enzyme to react testing library

* refactor: remove empty file
2022-12-01 11:51:33 +05:00
Abdullah Waheed
a6a1d94d92 refactor: updated renovate config to auto update minor and patch versions of edx dependencies 2022-11-30 13:25:15 +00:00
edX requirements bot
e54de547f6 fix: -t flag added in pull translation command (#695) 2022-11-30 16:46:54 +05:00
renovate[bot]
574cfb91c2 fix(deps): update dependency jslib-html5-camera-photo to v3.3.4 2022-11-28 12:07:44 +00:00
renovate[bot]
5bdf0a4978 chore(deps): update dependency @edx/frontend-build to v12.4.0 2022-11-28 08:40:57 +00:00
Jenkins
cd8dee1731 chore(i18n): update translations 2022-11-27 16:03:29 -05:00
Andrew Shultz
0e7d2c048d Merge pull request #694 from openedx/ashultz0/more-coppa-rewording
chore: trivial changes to compliance form text
2022-11-22 12:52:58 -05:00
Andy Shultz
79c4a14f6f chore: trivial changes to compliance form text 2022-11-22 10:06:56 -05:00
Muhammad Abdullah Waheed
de8977347a Merge pull request #692 from openedx/bilalqamar95/dependabot-vulnerabilities
refactor: bumped minimatch, recursive-readdir & loader-utils
2022-11-22 16:01:00 +05:00
renovate[bot]
783f78a9ef fix(deps): update dependency core-js to v3.26.1 2022-11-21 13:28:16 +00:00
Bilal Qamar
c1fa6efb30 refactor: bumped minimatch, recursive-readdir & loader-utils 2022-11-21 16:09:38 +05:00
renovate[bot]
b3cd370d8e fix(deps): update dependency regenerator-runtime to v0.13.11 2022-11-21 10:20:41 +00:00
renovate[bot]
8cb416d142 fix(deps): update dependency @edx/frontend-component-header to v3.4.1 2022-11-15 01:10:31 +00:00
renovate[bot]
dbd4faf558 fix(deps): update dependency @edx/frontend-component-footer to v11.5.1 2022-11-14 22:15:50 +00:00
Jenkins
92c8f17e2a chore(i18n): update translations 2022-11-13 16:03:26 -05:00
Muhammad Abdullah Waheed
c858966035 Supported Transifex languages in Makefile (#641)
* feat: added new translations in Makefile and updated all the translations

* refactor: updated i18n index file to fix language errors
2022-11-08 18:42:27 +05:00
Muhammad Abdullah Waheed
547d55a31f Paragon form component deprecations (#612)
* refactor: removed deprecated paragon components from CoachingToggle and used alternatives

* refactor: removed deprecated paragon components from ConfirmationModal and used alternatives

* refactor: removed deprecations from EditableField and created separate component for SelectField

* refactor: updated DemographicsSection to use new select component

* refactor: removed deprecations from EmailField and used alternatives

* refactor: removed deprecated Input from CoachingConsentForm

* refactor: removed deprecated Input from DemographicsSection

* refactor: removed deprecated Input from SummaryPanel component

* refactor: removed deprecated CheckBox and used Form.CheckBox

* refactor: fixed unit tests

* refactor: changes based on PR reviews

* fix: linting issue
2022-11-08 18:42:09 +05:00
renovate[bot]
f78420511e fix(deps): update dependency react-router-hash-link to v2 (#262)
* fix(deps): update dependency react-router-hash-link to v2

* refactor: update snapshot tests

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: mashal-m <mashal.malik@arbisoft.com>
2022-11-08 13:23:24 +05:00
renovate[bot]
e3ad6e6e54 fix(deps): update dependency form-urlencoded to v4.5.1 (#133)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-08 11:45:54 +05:00
renovate[bot]
c6ffc51a5d fix(deps): update dependency @tensorflow/tfjs-converter to v3.21.0 (#408)
* fix(deps): update dependency @tensorflow/tfjs-converter to v3.21.0

* fix: updated package-lock to resolve dependency tree issue

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Bilal Qamar <59555732+BilalQamar95@users.noreply.github.com>
Co-authored-by: Abdullah Waheed <abdullah.waheed@arbisoft.com>
2022-11-08 10:47:14 +05:00
renovate[bot]
9b28469afd fix(deps): update dependency @tensorflow/tfjs-core to v3.21.0 (#409)
* fix(deps): update dependency @tensorflow/tfjs-core to v3.21.0

* fix: updated package-lock to resolve dependency tree issue

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Bilal Qamar <59555732+BilalQamar95@users.noreply.github.com>
Co-authored-by: Abdullah Waheed <abdullah.waheed@arbisoft.com>
2022-11-08 10:17:16 +05:00
renovate[bot]
2bb1388a45 fix(deps): update dependency @fortawesome/react-fontawesome to v0.2.0 2022-11-07 15:15:03 +00:00
renovate[bot]
bf0d1379f6 fix(deps): update dependency long to v5.2.1 2022-11-07 13:56:08 +00:00
renovate[bot]
0d9bc5988d fix(deps): update dependency @edx/frontend-component-footer to v11.4.1 2022-11-07 10:56:46 +00:00
renovate[bot]
3a2075de9c fix(deps): update dependency @edx/frontend-component-footer to v11.3.1 (#672)
* fix(deps): update dependency @edx/frontend-component-footer to v11.3.1

* fix: updated package-lock to resolve dependency tree issue

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Bilal Qamar <59555732+BilalQamar95@users.noreply.github.com>
Co-authored-by: Abdullah Waheed <abdullah.waheed@arbisoft.com>
2022-11-07 12:30:53 +05:00
renovate[bot]
ef6239a807 chore(deps): update dependency enzyme-adapter-react-16 to v1.15.7 2022-11-07 07:19:43 +00:00
renovate[bot]
8cb9df6d89 fix(deps): update dependency @edx/paragon to v19.25.3 2022-10-31 13:28:35 +00:00
renovate[bot]
fa856b54bf fix(deps): update dependency @edx/frontend-component-header to v3.3.0 2022-10-31 10:16:07 +00:00
Muhammad Abdullah Waheed
e9f6acff27 Merge pull request #673 from openedx/abdullahwaheed/eslint-issues-fix
fix: migrated functions to arrow functions to fix linting
2022-10-24 18:02:37 +05:00
Abdullah Waheed
dc26da9cc1 fix: migrated functions to arrow functions to fix linting 2022-10-24 15:53:58 +05:00
renovate[bot]
9dd05761fd chore(deps): update dependency @edx/frontend-build to v12.3.0 2022-10-24 08:26:58 +00:00
renovate[bot]
0d5b86df57 fix(deps): update dependency regenerator-runtime to v0.13.10 2022-10-17 08:57:06 +00:00
renovate[bot]
d8eb6e9da5 fix(deps): update dependency react-redux to v7.2.9 2022-10-17 08:49:23 +00:00
162 changed files with 13003 additions and 35920 deletions

5
.env
View File

@@ -1,6 +1,5 @@
ACCESS_TOKEN_COOKIE_NAME=''
BASE_URL=''
COACHING_ENABLED=''
CREDENTIALS_BASE_URL=''
CSRF_TOKEN_API_PATH=''
DEMOGRAPHICS_BASE_URL=''
@@ -26,7 +25,11 @@ STUDIO_BASE_URL=''
SUPPORT_URL=''
USER_INFO_COOKIE_NAME=''
ENABLE_COPPA_COMPLIANCE=''
ENABLE_ACCOUNT_DELETION=''
ENABLE_DOB_UPDATE=''
MARKETING_EMAILS_OPT_IN=''
APP_ID=
MFE_CONFIG_API_URL=
PASSWORD_RESET_SUPPORT_LINK=''
LEARNER_FEEDBACK_URL=''
SUPPORT_URL_TO_UNLINK_SOCIAL_MEDIA_ACCOUNT='https://support.edx.org/hc/en-us/articles/207206067'

View File

@@ -1,6 +1,5 @@
ACCESS_TOKEN_COOKIE_NAME='edx-jwt-cookie-header-payload'
BASE_URL='localhost:1997'
COACHING_ENABLED=''
CREDENTIALS_BASE_URL='http://localhost:18150'
CSRF_TOKEN_API_PATH='/csrf/api/v1/token'
DEMOGRAPHICS_BASE_URL='http://localhost:18360'
@@ -27,8 +26,11 @@ STUDIO_BASE_URL=''
SUPPORT_URL='http://localhost:18000/support'
USER_INFO_COOKIE_NAME='edx-user-info'
ENABLE_COPPA_COMPLIANCE=''
ENABLE_ACCOUNT_DELETION=''
ENABLE_DOB_UPDATE=''
MARKETING_EMAILS_OPT_IN=''
APP_ID=
MFE_CONFIG_API_URL=
PASSWORD_RESET_SUPPORT_LINK='mailto:support@example.com'
LEARNER_FEEDBACK_URL=''
SUPPORT_URL_TO_UNLINK_SOCIAL_MEDIA_ACCOUNT='https://support.edx.org/hc/en-us/articles/207206067'

View File

@@ -1,6 +1,5 @@
ACCESS_TOKEN_COOKIE_NAME='edx-jwt-cookie-header-payload'
BASE_URL='localhost:1997'
COACHING_ENABLED=''
CREDENTIALS_BASE_URL='http://localhost:18150'
CSRF_TOKEN_API_PATH='/csrf/api/v1/token'
DEMOGRAPHICS_BASE_URL='http://localhost:18360'
@@ -26,7 +25,10 @@ STUDIO_BASE_URL=''
SUPPORT_URL='http://localhost:18000/support'
USER_INFO_COOKIE_NAME='edx-user-info'
ENABLE_COPPA_COMPLIANCE=''
ENABLE_ACCOUNT_DELETION=''
ENABLE_DOB_UPDATE=''
MARKETING_EMAILS_OPT_IN=''
APP_ID=
MFE_CONFIG_API_URL=
LEARNER_FEEDBACK_URL=''
SUPPORT_URL_TO_UNLINK_SOCIAL_MEDIA_ACCOUNT='https://support.edx.org/hc/en-us/articles/207206067'

View File

@@ -1,4 +1,4 @@
// eslint-disable-next-line import/no-extraneous-dependencies
const { createConfig } = require('@edx/frontend-build');
const { createConfig } = require('@openedx/frontend-build');
module.exports = createConfig('eslint');

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

@@ -9,18 +9,17 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node: [16]
npm: [8.5.0]
npm-test:
- i18n_extract
- lint
- test
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Setup Nodejs Env
run: echo "NODE_VER=`cat .nvmrc`" >> $GITHUB_ENV
- uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node }}
- run: npm install -g npm@${{ matrix.npm }}
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,5 +10,5 @@ on:
jobs:
version-check:
uses: openedx/.github/.github/workflows/lockfileversion-check.yml@master
uses: openedx/.github/.github/workflows/lockfile-check.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

@@ -1,41 +0,0 @@
name: Update Browserlist DB
on:
schedule:
- cron: '0 0 * * 1'
workflow_dispatch:
jobs:
update-dep:
runs-on: ubuntu-latest
strategy:
matrix:
node: [16]
npm: [8.5.x]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node }}
- run: npm install -g npm@${{ matrix.npm }}
- run: make requirements
- name: Update dependencies
run: npx browserslist@latest --update-db
- name: setup testeng-ci
run: |
git clone https://github.com/edx/testeng-ci.git
cd $GITHUB_WORKSPACE/testeng-ci
pip install -r requirements/base.txt
- name: create pull request
id: createpullrequest
env:
GITHUB_TOKEN: ${{ secrets.requirements_bot_github_token }}
GITHUB_USER_EMAIL: ${{ secrets.requirements_bot_github_email }}
run: |
cd $GITHUB_WORKSPACE/testeng-ci
python -m jenkins.pull_request_creator --repo-root=$GITHUB_WORKSPACE \
--target-branch="master" --base-branch-name="update-browserslist" \
--commit-message="chore: update browserslist" --pr-title="Update browserslist DB" \
--pr-body="Updated browserlist DB" --delete-old-pull-requests --output-pr-url-for-github-action

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 }}

1
.gitignore vendored
View File

@@ -17,3 +17,4 @@ temp/babel-plugin-react-intl
/temp
/.vscode
/module.config.js
src/i18n/messages/

2
.nvmrc
View File

@@ -1 +1 @@
v16
18

View File

@@ -1,9 +0,0 @@
[main]
host = https://www.transifex.com
[o:open-edx:p:edx-platform:r:frontend-app-account]
file_filter = src/i18n/messages/<lang>.json
source_file = src/i18n/transifex_input.json
source_lang = en
type = KEYVALUEJSON

33
Makefile Executable file → Normal file
View File

@@ -1,15 +1,12 @@
export TRANSIFEX_RESOURCE = frontend-app-account
transifex_resource = frontend-app-account
transifex_langs = "ar,fr,es_419,zh_CN"
intl_imports = ./node_modules/.bin/intl-imports.js
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
transifex_temp = ./temp/babel-plugin-formatjs
NPM_TESTS=build i18n_extract lint test
@@ -41,20 +38,18 @@ detect_changed_source_translations:
# Checking for changed translations...
git diff --exit-code $(i18n)
# Pushes translations to Transifex. You must run make extract_translations first.
push_translations:
# Pushing strings to Transifex...
tx push -s
# Fetching hashes from Transifex...
./node_modules/@edx/reactifex/bash_scripts/get_hashed_strings_v3.sh
# Writing out comments to file...
$(transifex_utils) $(transifex_temp) --comments --v3-scripts-path
# Pushing comments to Transifex...
./node_modules/@edx/reactifex/bash_scripts/put_comments_v3.sh
# Pulls translations from Transifex.
pull_translations:
tx pull -f --mode reviewed --languages=$(transifex_langs)
rm -rf src/i18n/messages
mkdir src/i18n/messages
cd src/i18n/messages \
&& atlas pull $(ATLAS_OPTIONS) \
translations/frontend-platform/src/i18n/messages:frontend-platform \
translations/paragon/src/i18n/messages:paragon \
translations/frontend-component-footer/src/i18n/messages:frontend-component-footer \
translations/frontend-component-header/src/i18n/messages:frontend-component-header \
translations/frontend-app-account/src/i18n/messages:frontend-app-account
$(intl_imports) frontend-platform paragon frontend-component-header frontend-component-footer frontend-app-account
# This target is used by Travis.
validate-no-uncommitted-package-lock-changes:

View File

@@ -1,12 +1,13 @@
####################
frontend-app-account
####################
|ci-badge| |Codecov| |npm_version| |npm_downloads| |license| |semantic-release|
frontend-app-account
====================
Please tag **@edx/community-engineering** on any PRs or issues. Thanks!
Introduction
------------
********
Purpose
********
This is a micro-frontend application responsible for the display and updating of a user's account information.
@@ -20,8 +21,28 @@ In this MFE: Private user settings UIs. Public facing profile is in a `separate
- IDV (Identity Verification)
***************
Getting Started
***************
Prerequisites
=============
The `devstack`_ is currently recommended as a development environment for your
new MFE. If you start it with ``make dev.up.lms`` that should give you
everything you need as a companion to this frontend.
Note that it is also possible to use `Tutor`_ to develop an MFE. You can refer
to the `relevant tutor-mfe documentation`_ to get started using it.
.. _Devstack: https://github.com/openedx/devstack
.. _Tutor: https://github.com/overhangio/tutor
.. _relevant tutor-mfe documentation: https://github.com/overhangio/tutor-mfe#mfe-development
Installation
------------
============
This MFE is bundled with `Devstack <https://github.com/openedx/devstack>`_, see the `Getting Started <https://github.com/openedx/devstack#getting-started>`_ section for setup instructions.
@@ -42,8 +63,14 @@ This MFE is bundled with `Devstack <https://github.com/openedx/devstack>`_, see
.. image:: ./docs/images/localhost_preview.png
Plugins
=======
This MFE can be customized using `Frontend Plugin Framework <https://github.com/openedx/frontend-plugin-framework>`_.
The parts of this MFE that can be customized in that manner are documented `here </src/plugin-slots>`_.
Environment Variables/Setup Notes
---------------------------------
=================================
This MFE is configured via environment variables supplied at build time. All micro-frontends have a shared set of required environment variables, as documented in the Open edX Developer Guide under `Required Environment Variables <https://edx.readthedocs.io/projects/edx-developer-docs/en/latest/developers_guide/micro_frontends_in_open_edx.html#required-environment-variables>`__.
@@ -55,17 +82,28 @@ Example: ``https://support.example.com``
The fully-qualified URL to the support page in the target environment.
``PASSWORD_RESET_SUPPORT_LINK``
Examples:
- ``https://support.edx.org/hc/en-us/articles/206212088-What-if-I-did-not-receive-a-password-reset-message-``
- ``mailto:support@example.com``
The fully-qualified URL to the support page or email to request the support from in the target environment.
``ENABLE_ACCOUNT_DELETION``
Example: ``'false'`` | ``''`` (empty strings are true)
Enable the account deletion option, defaults to true.
To disable account deletion set ``ENABLE_ACCOUNT_DELETION`` to ``'false'`` (string), otherwise it will default to true.
edX-specific Environment Variables
**********************************
==================================
Furthermore, there are several edX-specific environment variables that enable integrations with closed-source services private to the edX organization, and are unsupported in Open edX. Enabling these environment variables will result in undefined behavior in Open edX installations:
``COACHING_ENABLED``
Example: ``true`` | ``''`` (empty strings are falsy)
Enables support for a section of the micro-frontend that helps users arrange for coaching sessions. Integrates with a private coaching plugin and is only used by edx.org.
``ENABLE_DEMOGRAPHICS_COLLECTION``
Example: ``true`` | ``''`` (empty strings are falsy)
@@ -87,18 +125,101 @@ Example build syntax with a single environment variable:
For more information see the document: `Micro-frontend applications in Open
edX <https://edx.readthedocs.io/projects/edx-developer-docs/en/latest/developers_guide/micro_frontends_in_open_edx.html#required-environment-variables>`__.
Cloning and Startup
===================
.. code-block::
1. Clone your new repo:
``git clone https://github.com/openedx/frontend-app-account.git``
2. Use node v18.x.
The current version of the micro-frontend build scripts support node 18.
Using other major versions of node *may* work, but this is unsupported. For
convenience, this repository includes an .nvmrc file to help in setting the
correct node version via `nvm <https://github.com/nvm-sh/nvm>`_.
3. Install npm dependencies:
``cd frontend-app-account && npm ci``
4. Start the dev server:
``npm start``
Known Issues
------------
===========
None
Development Roadmap
-------------------
===================
We don't have anything planned for the core of the MFE (the account settings page) - this MFE is currently in maintenance mode.
There may be a replacement for IDV coming down the pipe, so that may be DEPRed.
In the future, it's possible that demographics could be modeled as a plugin rather than being hard-coded into this MFE.
License
=======
The code in this repository is licensed under the AGPLv3 unless otherwise
noted.
Please see `LICENSE <LICENSE>`_ for details.
Contributing
============
Contributions are very welcome. Please read `How To Contribute`_ for details.
.. _How To Contribute: https://openedx.org/r/how-to-contribute
This project is currently accepting all types of contributions, bug fixes,
security fixes, maintenance work, or new features. However, please make sure
to have a discussion about your new feature idea with the maintainers prior to
beginning development to maximize the chances of your change being accepted.
You can start a conversation by creating a new issue on this repo summarizing
your idea.
Getting Help
===========
If you're having trouble, we have discussion forums at
https://discuss.openedx.org where you can connect with others in the community.
Our real-time conversations are on Slack. You can request a `Slack
invitation`_, then join our `community Slack workspace`_. Because this is a
frontend repository, the best place to discuss it would be in the `#wg-frontend
channel`_.
For anything non-trivial, the best path is to open an issue in this repository
with as many details about the issue you are facing as you can provide.
https://github.com/openedx/frontend-app-account/issues
For more information about these options, see the `Getting Help`_ page.
.. _Slack invitation: https://openedx.org/slack
.. _community Slack workspace: https://openedx.slack.com/
.. _#wg-frontend channel: https://openedx.slack.com/archives/C04BM6YC7A6
.. _Getting Help: https://openedx.org/community/connect
The Open edX Code of Conduct
============================
All community members are expected to follow the `Open edX Code of Conduct`_.
.. _Open edX Code of Conduct: https://openedx.org/code-of-conduct/
Reporting Security Issues
=========================
Please do not report security issues in public. Please email security@openedx.org.
==============================

View File

@@ -1,4 +1,4 @@
const { createConfig } = require('@edx/frontend-build');
const { createConfig } = require('@openedx/frontend-build');
module.exports = createConfig('jest', {
setupFilesAfterEnv: [

39263
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,7 @@
},
"scripts": {
"build": "fedx-scripts webpack",
"i18n_extract": "BABEL_ENV=i18n fedx-scripts babel src --quiet > /dev/null",
"i18n_extract": "fedx-scripts formatjs extract",
"lint": "fedx-scripts eslint --ext .js --ext .jsx .",
"snapshot": "fedx-scripts jest --updateSnapshot",
"start": "fedx-scripts webpack-dev-server --progress",
@@ -27,27 +27,28 @@
"extends @edx/browserslist-config"
],
"dependencies": {
"@edx/brand": "npm:@edx/brand-openedx@1.1.0",
"@edx/frontend-component-footer": "11.2.1",
"@edx/frontend-component-header": "3.2.1",
"@edx/frontend-platform": "2.6.2",
"@edx/paragon": "19.20.0",
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
"@edx/frontend-component-footer": "^13.2.0",
"@edx/frontend-component-header": "5.3.0",
"@edx/frontend-platform": "8.0.1",
"@edx/openedx-atlas": "^0.6.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.1.16",
"@fortawesome/react-fontawesome": "0.2.0",
"@openedx/frontend-plugin-framework": "^1.1.2",
"@openedx/paragon": "22.0.0",
"@tensorflow-models/blazeface": "0.0.7",
"@tensorflow/tfjs-converter": "3.18.0",
"@tensorflow/tfjs-core": "3.18.0",
"@tensorflow/tfjs-converter": "3.21.0",
"@tensorflow/tfjs-core": "3.21.0",
"bowser": "2.11.0",
"classnames": "2.3.2",
"core-js": "3.19.3",
"classnames": "2.5.1",
"core-js": "3.37.0",
"font-awesome": "4.7.0",
"form-urlencoded": "4.0.1",
"form-urlencoded": "6.1.4",
"formdata-polyfill": "4.0.10",
"history": "4.10.1",
"jslib-html5-camera-photo": "3.1.8",
"jslib-html5-camera-photo": "3.3.4",
"lodash.camelcase": "4.3.0",
"lodash.debounce": "4.0.8",
"lodash.findindex": "4.6.0",
@@ -57,38 +58,37 @@
"lodash.omit": "4.5.0",
"lodash.pick": "4.4.0",
"lodash.pickby": "4.6.0",
"long": "5.2.0",
"lodash.snakecase": "4.1.1",
"long": "5.2.3",
"memoize-one": "5.2.1",
"prop-types": "15.7.2",
"qs": "6.10.3",
"react": "16.14.0",
"react-dom": "16.14.0",
"prop-types": "15.8.1",
"qs": "6.12.1",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-helmet": "6.1.0",
"react-redux": "7.2.8",
"react-router": "5.2.1",
"react-router-dom": "5.3.0",
"react-router-hash-link": "1.2.2",
"react-redux": "7.2.9",
"react-router": "6.23.0",
"react-router-dom": "6.23.0",
"react-router-hash-link": "2.4.3",
"react-scrollspy": "3.4.3",
"react-transition-group": "4.4.5",
"redux": "4.1.2",
"redux": "4.2.1",
"redux-devtools-extension": "2.13.9",
"redux-logger": "3.0.6",
"redux-saga": "1.1.3",
"redux-thunk": "2.3.0",
"regenerator-runtime": "0.13.9",
"reselect": "4.0.0",
"redux-saga": "1.3.0",
"redux-thunk": "2.4.2",
"regenerator-runtime": "0.14.1",
"reselect": "4.1.8",
"universal-cookie": "4.0.4"
},
"devDependencies": {
"@edx/browserslist-config": "1.1.1",
"@edx/frontend-build": "12.0.6",
"@edx/browserslist-config": "1.2.0",
"@edx/reactifex": "1.1.0",
"@testing-library/jest-dom": "5.16.5",
"@openedx/frontend-build": "14.0.3",
"@testing-library/jest-dom": "6.4.5",
"@testing-library/react": "12.1.5",
"enzyme": "3.11.0",
"enzyme-adapter-react-16": "1.15.6",
"react-test-renderer": "16.14.0",
"react-test-renderer": "17.0.2",
"reactifex": "1.1.1",
"redux-mock-store": "1.5.4"
}
}
}

View File

@@ -1,17 +1,148 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en-us">
<head>
<title>Account | <%= process.env.SITE_NAME %></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="<%=htmlWebpackPlugin.options.FAVICON_URL%>" type="image/x-icon" />
<% if (process.env.OPTIMIZELY_PROJECT_ID) { %>
<script
src="<%= process.env.MARKETING_SITE_BASE_URL %>/optimizelyjs/<%= process.env.OPTIMIZELY_PROJECT_ID %>.js"
></script>
<% } %>
<title>Account | <%= process.env.SITE_NAME %></title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
rel="shortcut icon"
href="<%=htmlWebpackPlugin.options.FAVICON_URL%>"
type="image/x-icon"
/>
<% if (process.env.OPTIMIZELY_PROJECT_ID) { %>
<script src="<%= process.env.MARKETING_SITE_BASE_URL %>/optimizelyjs/<%= process.env.OPTIMIZELY_PROJECT_ID %>.js"></script>
<% } %>
</head>
<body>
<!-- begin usabilla live embed code -->
<script defer type="text/javascript">
window.lightningjs ||
(function (n) {
var e = "lightningjs";
function t(e, t) {
var r, i, a, o, d, c;
return (
t && (t += (/\?/.test(t) ? "&" : "?") + "lv=1"),
n[e] ||
((r = window),
(i = document),
(a = e),
(o = i.location.protocol),
(d = "load"),
(c = 0),
(function () {
n[a] = function () {
var t = arguments,
i = this,
o = ++c,
d = (i && i != r && i.id) || 0;
function s() {
return (s.id = o), n[a].apply(s, arguments);
}
return (
(e.s = e.s || []).push([o, d, t]),
(s.then = function (n, t, r) {
var i = (e.fh[o] = e.fh[o] || []),
a = (e.eh[o] = e.eh[o] || []),
d = (e.ph[o] = e.ph[o] || []);
return (
n && i.push(n), t && a.push(t), r && d.push(r), s
);
}),
s
);
};
var e = (n[a]._ = {});
function s() {
e.P(d), (e.w = 1), n[a]("_load");
}
(e.fh = {}),
(e.eh = {}),
(e.ph = {}),
(e.l = t
? t.replace(/^\/\//, ("https:" == o ? o : "http:") + "//")
: t),
(e.p = { 0: +new Date() }),
(e.P = function (n) {
e.p[n] = new Date() - e.p[0];
}),
e.w && s(),
r.addEventListener
? r.addEventListener(d, s, !1)
: r.attachEvent("onload", s);
var l = function () {
function n() {
return [
"<!DOCTYPE ",
o,
"><",
o,
"><head></head><",
t,
"><",
r,
' src="',
e.l,
'"></',
r,
"></",
t,
"></",
o,
">",
].join("");
}
var t = "body",
r = "script",
o = "html",
d = i[t];
if (!d) return setTimeout(l, 100);
e.P(1);
var c,
s = i.createElement("div"),
h = s.appendChild(i.createElement("div")),
u = i.createElement("iframe");
(s.style.display = "none"),
(d.insertBefore(s, d.firstChild).id = "lightningjs-" + a),
(u.frameBorder = "0"),
(u.id = "lightningjs-frame-" + a),
/MSIE[ ]+6/.test(navigator.userAgent) &&
(u.src = "javascript:false"),
(u.allowTransparency = "true"),
h.appendChild(u);
try {
u.contentWindow.document.open();
} catch (n) {
(e.domain = i.domain),
(c =
"javascript:var d=document.open();d.domain='" +
i.domain +
"';"),
(u.src = c + "void(0);");
}
try {
var p = u.contentWindow.document;
p.write(n()), p.close();
} catch (e) {
u.src =
c +
'd.write("' +
n().replace(/"/g, String.fromCharCode(92) + '"') +
'");d.close();';
}
e.P(2);
};
e.l && l();
})()),
(n[e].lv = "1"),
n[e]
);
}
var r = (window.lightningjs = t(e));
(r.require = t), (r.modules = n);
})({});
</script>
<!-- end usabilla live embed code -->
<div id="root"></div>
</body>
</html>

View File

@@ -22,6 +22,11 @@
"pin"
],
"automerge": true
},
{
"matchPackagePatterns": ["@edx", "@openedx"],
"matchUpdateTypes": ["minor", "patch"],
"automerge": true
}
],
"timezone": "America/New_York"

View File

@@ -1,5 +1,5 @@
import { AppContext } from '@edx/frontend-platform/react';
import { getConfig, history, getQueryParameters } from '@edx/frontend-platform';
import { getConfig, getQueryParameters } from '@edx/frontend-platform';
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
@@ -15,8 +15,8 @@ import {
} from '@edx/frontend-platform/i18n';
import {
Button, Hyperlink, Icon, Alert,
} from '@edx/paragon';
import { CheckCircle, Error, WarningFilled } from '@edx/paragon/icons';
} from '@openedx/paragon';
import { CheckCircle, Error, WarningFilled } from '@openedx/paragon/icons';
import messages from './AccountSettingsPage.messages';
import {
@@ -31,6 +31,7 @@ import PageLoading from './PageLoading';
import JumpNav from './JumpNav';
import DeleteAccount from './delete-account';
import EditableField from './EditableField';
import EditableSelectField from './EditableSelectField';
import ResetPassword from './reset-password';
import NameChange from './name-change';
import ThirdPartyAuth from './third-party-auth';
@@ -44,24 +45,19 @@ import {
GENDER_OPTIONS,
COUNTRY_WITH_STATES,
COPPA_COMPLIANCE_YEAR,
WORK_EXPERIENCE_OPTIONS,
getStatesList,
} from './data/constants';
import { fetchSiteLanguages } from './site-language';
import CoachingToggle from './coaching/CoachingToggle';
import DemographicsSection from './demographics/DemographicsSection';
import { fetchCourseList } from '../notification-preferences/data/thunks';
import { withLocation, withNavigate } from './hoc';
class AccountSettingsPage extends React.Component {
constructor(props, context) {
super(props, context);
// If there is a "duplicate_provider" query parameter, that's the backend's
// way of telling us that the provider account the user tried to link is already linked
// to another user account on the platform. We use this to display a message to that effect,
// and remove the parameter from the URL.
const duplicateTpaProvider = getQueryParameters().duplicate_provider;
if (duplicateTpaProvider !== undefined) {
history.replace(history.location.pathname);
}
this.state = {
duplicateTpaProvider,
};
@@ -78,8 +74,9 @@ class AccountSettingsPage extends React.Component {
}
componentDidMount() {
this.props.fetchCourseList();
this.props.fetchSettings();
this.props.fetchSiteLanguages();
this.props.fetchSiteLanguages(this.props.navigate);
sendTrackingLogEvent('edx.user.settings.viewed', {
page: 'account',
visibility: null,
@@ -146,6 +143,10 @@ class AccountSettingsPage extends React.Component {
value: key,
label: this.props.intl.formatMessage(messages[`account.settings.field.gender.options.${key || 'empty'}`]),
})),
workExperienceOptions: WORK_EXPERIENCE_OPTIONS.map(key => ({
value: key,
label: key === '' ? this.props.intl.formatMessage(messages['account.settings.field.work.experience.options.empty']) : key,
})),
}));
handleEditableFieldChange = (name, value) => {
@@ -153,7 +154,17 @@ class AccountSettingsPage extends React.Component {
};
handleSubmit = (formId, values) => {
this.props.saveSettings(formId, values);
const { formValues } = this.props;
let extendedProfileObject = {};
if ('extended_profile' in formValues && formValues.extended_profile.some((field) => field.field_name === formId)) {
extendedProfileObject = {
extended_profile: formValues.extended_profile.map(field => (field.field_name === formId
? { ...field, field_value: values }
: field)),
};
}
this.props.saveSettings(formId, values, extendedProfileObject);
};
handleSubmitProfileName = (formId, values) => {
@@ -199,6 +210,12 @@ class AccountSettingsPage extends React.Component {
return null;
}
// If there is a "duplicate_provider" query parameter, that's the backend's
// way of telling us that the provider account the user tried to link is already linked
// to another user account on the platform. We use this to display a message to that effect,
// and remove the parameter from the URL.
this.props.navigate(this.props.location, { replace: true });
return (
<div>
<Alert variant="danger">
@@ -467,13 +484,15 @@ class AccountSettingsPage extends React.Component {
yearOfBirthOptions,
educationLevelOptions,
genderOptions,
workExperienceOptions,
} = this.getLocalizedOptions(this.context.locale, this.props.formValues.country);
// Show State field only if the country is US (could include Canada later)
const showState = this.props.formValues.country === COUNTRY_WITH_STATES;
const { verifiedName } = this.props;
const hasWorkExperience = !!this.props.formValues?.extended_profile?.find(field => field.field_name === 'work_experience');
const timeZoneOptions = this.getLocalizedTimeZoneOptions(
this.props.timeZoneOptions,
this.props.countryTimeZoneOptions,
@@ -609,7 +628,7 @@ class AccountSettingsPage extends React.Component {
<ResetPassword email={this.props.formValues.email} />
{(!getConfig().ENABLE_COPPA_COMPLIANCE)
&& (
<EditableField
<EditableSelectField
name="year_of_birth"
type="select"
label={this.props.intl.formatMessage(messages['account.settings.field.dob'])}
@@ -619,7 +638,7 @@ class AccountSettingsPage extends React.Component {
{...editableFieldProps}
/>
)}
<EditableField
<EditableSelectField
name="country"
type="select"
value={this.props.formValues.country}
@@ -635,7 +654,7 @@ class AccountSettingsPage extends React.Component {
/>
{showState
&& (
<EditableField
<EditableSelectField
name="state"
type="select"
value={this.props.formValues.state}
@@ -657,16 +676,18 @@ class AccountSettingsPage extends React.Component {
{this.props.intl.formatMessage(messages['account.settings.section.profile.information'])}
</h2>
<EditableField
<EditableSelectField
name="level_of_education"
type="select"
value={this.props.formValues.level_of_education}
options={educationLevelOptions}
options={getConfig().ENABLE_COPPA_COMPLIANCE
? educationLevelOptions.filter(option => option.value !== 'el')
: educationLevelOptions}
label={this.props.intl.formatMessage(messages['account.settings.field.education'])}
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.education.empty'])}
{...editableFieldProps}
/>
<EditableField
<EditableSelectField
name="gender"
type="select"
value={this.props.formValues.gender}
@@ -675,7 +696,19 @@ class AccountSettingsPage extends React.Component {
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.gender.empty'])}
{...editableFieldProps}
/>
<EditableField
{hasWorkExperience
&& (
<EditableSelectField
name="work_experience"
type="select"
value={this.props.formValues?.extended_profile?.find(field => field.field_name === 'work_experience')?.field_value}
options={workExperienceOptions}
label={this.props.intl.formatMessage(messages['account.settings.field.work.experience'])}
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.work.experience.empty'])}
{...editableFieldProps}
/>
)}
<EditableSelectField
name="language_proficiencies"
type="select"
value={this.props.formValues.language_proficiencies}
@@ -684,15 +717,6 @@ class AccountSettingsPage extends React.Component {
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.language.proficiencies.empty'])}
{...editableFieldProps}
/>
{getConfig().COACHING_ENABLED
&& this.props.formValues.coaching.eligible_for_coaching
&& (
<CoachingToggle
name="coaching"
phone_number={this.props.formValues.phone_number}
coaching={this.props.formValues.coaching}
/>
)}
</div>
{getConfig().ENABLE_DEMOGRAPHICS_COLLECTION && this.renderDemographicsSection()}
<div className="account-section pt-3 mb-5" id="social-media">
@@ -738,7 +762,7 @@ class AccountSettingsPage extends React.Component {
</h2>
<BetaLanguageBanner />
<EditableField
<EditableSelectField
name="siteLanguage"
type="select"
options={this.props.siteLanguageOptions}
@@ -747,7 +771,7 @@ class AccountSettingsPage extends React.Component {
helpText={this.props.intl.formatMessage(messages['account.settings.field.site.language.help.text'])}
{...editableFieldProps}
/>
<EditableField
<EditableSelectField
name="time_zone"
type="select"
value={this.props.formValues.time_zone}
@@ -774,12 +798,15 @@ class AccountSettingsPage extends React.Component {
<ThirdPartyAuth />
</div>
<div className="account-section pt-3 mb-5" id="delete-account" ref={this.navLinkRefs['#delete-account']}>
<DeleteAccount
isVerifiedAccount={this.props.isActive}
hasLinkedTPA={hasLinkedTPA}
/>
</div>
{getConfig().ENABLE_ACCOUNT_DELETION
&& (
<div className="account-section pt-3 mb-5" id="delete-account" ref={this.navLinkRefs['#delete-account']}>
<DeleteAccount
isVerifiedAccount={this.props.isActive}
hasLinkedTPA={hasLinkedTPA}
/>
</div>
)}
</>
);
@@ -816,12 +843,12 @@ class AccountSettingsPage extends React.Component {
</h1>
<div>
<div className="row">
<div className="col-md-3">
<div className="col-md-2">
<JumpNav
displayDemographicsLink={this.props.formValues.shouldDisplayDemographicsSection}
/>
</div>
<div className="col-md-9">
<div className="col-md-10">
{loading ? this.renderLoading() : null}
{loaded ? this.renderContent() : null}
{loadingError ? this.renderError() : null}
@@ -852,6 +879,7 @@ AccountSettingsPage.propTypes = {
country: PropTypes.string,
level_of_education: PropTypes.string,
gender: PropTypes.string,
extended_profile: PropTypes.string,
language_proficiencies: PropTypes.string,
pending_name_change: PropTypes.string,
phone_number: PropTypes.string,
@@ -859,11 +887,6 @@ AccountSettingsPage.propTypes = {
social_link_facebook: PropTypes.string,
social_link_twitter: PropTypes.string,
time_zone: PropTypes.string,
coaching: PropTypes.shape({
coaching_consent: PropTypes.bool.isRequired,
user: PropTypes.number.isRequired,
eligible_for_coaching: PropTypes.bool.isRequired,
}),
state: PropTypes.string,
shouldDisplayDemographicsSection: PropTypes.bool,
useVerifiedNameForCerts: PropTypes.bool.isRequired,
@@ -905,6 +928,7 @@ AccountSettingsPage.propTypes = {
saveSettings: PropTypes.func.isRequired,
fetchSettings: PropTypes.func.isRequired,
beginNameChange: PropTypes.func.isRequired,
fetchCourseList: PropTypes.func.isRequired,
tpaProviders: PropTypes.arrayOf(PropTypes.shape({
connected: PropTypes.bool,
})),
@@ -928,6 +952,8 @@ AccountSettingsPage.propTypes = {
proctored_exam_attempt_id: PropTypes.number,
}),
),
navigate: PropTypes.func.isRequired,
location: PropTypes.string.isRequired,
};
AccountSettingsPage.defaultProps = {
@@ -955,11 +981,12 @@ AccountSettingsPage.defaultProps = {
verifiedNameHistory: [],
};
export default connect(accountSettingsPageSelector, {
export default withLocation(withNavigate(connect(accountSettingsPageSelector, {
fetchCourseList,
fetchSettings,
saveSettings,
saveMultipleSettings,
updateDraft,
fetchSiteLanguages,
beginNameChange,
})(injectIntl(AccountSettingsPage));
})(injectIntl(AccountSettingsPage))));

View File

@@ -276,6 +276,16 @@ const messages = defineMessages({
defaultMessage: 'Year',
description: 'Label for account settings year of birth field.',
},
'account.settings.field.dob.month.default': {
id: 'account.settings.field.month.year.default',
defaultMessage: 'Select month',
description: 'Default label for account settings month of birth field.',
},
'account.settings.field.dob.year.default': {
id: 'account.settings.field.dob.year.default',
defaultMessage: 'Select year',
description: 'Default label for account settings year of birth field.',
},
'account.settings.field.dob.form.button': {
id: 'account.settings.field.dob.form.button',
defaultMessage: 'Please confirm your date of birth',
@@ -283,17 +293,17 @@ const messages = defineMessages({
},
'account.settings.field.dob.form.title': {
id: 'account.settings.field.dob.form.title',
defaultMessage: 'Confirm your date of birth',
defaultMessage: 'Enter your birth month and year',
description: 'Title of DOB form',
},
'account.settings.field.dob.form.help.text': {
id: 'account.settings.field.dob.form.help.text',
defaultMessage: 'We ask for birth date information to help us comply with our legal obligations.',
defaultMessage: 'We ask for birth month and year information to help us comply with our legal obligations.',
description: 'Help text for DOB form',
},
'account.settings.field.dob.form.success': {
id: 'account.settings.field.dob.form.success',
defaultMessage: 'Thank you for entering your birth date information.',
defaultMessage: 'Thank you for entering your information.',
description: 'Title of banner when date of birth is successfully entered',
},
'account.settings.field.month_of_birth.options.empty': {
@@ -401,8 +411,8 @@ const messages = defineMessages({
defaultMessage: 'No formal education',
description: 'Selected by the user to describe their education.',
},
'account.settings.field.education.levels.o': {
id: 'account.settings.field.education.levels.o',
'account.settings.field.education.levels.other': {
id: 'account.settings.field.education.levels.other',
defaultMessage: 'Other education',
description: 'Selected by the user if they have a type of education not described by the other choices.',
},
@@ -555,6 +565,26 @@ const messages = defineMessages({
defaultMessage: 'No value set.',
description: 'The placeholder for an empty but uneditable field when there is no administrator',
},
'notification.preferences.notifications.label': {
id: 'notification.preferences.notifications.label',
defaultMessage: 'Notifications',
description: 'Label for Notifications',
},
'account.settings.field.work.experience': {
id: 'account.settings.work.experience',
defaultMessage: 'Work Experience',
description: 'Label for account settings Work experience field.',
},
'account.settings.field.work.experience.empty': {
id: 'account.settings.field.work.experience.empty',
defaultMessage: 'Add work experience',
description: 'Placeholder for empty account settings work experience field.',
},
'account.settings.field.work.experience.options.empty': {
id: 'account.settings.field.work.experience.options.empty',
defaultMessage: 'Select work experience',
description: 'Placeholder for the work experience levels dropdown.',
},
});
export default messages;

View File

@@ -2,18 +2,16 @@ import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
function Alert(props) {
return (
<div className={classNames('alert d-flex align-items-start', props.className)}>
<div>
{props.icon}
</div>
<div>
{props.children}
</div>
const Alert = (props) => (
<div className={classNames('alert d-flex align-items-start', props.className)}>
<div>
{props.icon}
</div>
);
}
<div>
{props.children}
</div>
</div>
);
Alert.propTypes = {
className: PropTypes.string,

View File

@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { AppContext } from '@edx/frontend-platform/react';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { connect } from 'react-redux';
import { Button, Hyperlink } from '@edx/paragon';
import { Button, Hyperlink } from '@openedx/paragon';
import { betaLanguageBannerSelector } from './data/selectors';
import messages from './AccountSettingsPage.messages';
@@ -49,6 +49,9 @@ class BetaLanguageBanner extends React.Component {
render() {
const savedLanguage = this.getSiteLanguageEntry(this.context.locale);
if (!savedLanguage) {
return null;
}
const isSavedLanguageReleased = savedLanguage.released === true;
const noPreviousLanguageSet = this.props.siteLanguage.previousValue === null;
if (isSavedLanguageReleased || noPreviousLanguageSet) {

View File

@@ -2,15 +2,15 @@ import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import {
Form, StatefulButton, ModalDialog, ActionRow, useToggle, Button,
} from '@edx/paragon';
import React, { useCallback, useEffect } from 'react';
} from '@openedx/paragon';
import React, { useCallback, useEffect, useState } from 'react';
import { connect, useDispatch } from 'react-redux';
import messages from './AccountSettingsPage.messages';
import { YEAR_OF_BIRTH_OPTIONS } from './data/constants';
import { editableFieldSelector } from './data/selectors';
import { saveSettingsReset } from './data/actions';
function DOBModal(props) {
const DOBModal = (props) => {
const {
saveState,
error,
@@ -22,13 +22,23 @@ function DOBModal(props) {
// eslint-disable-next-line no-unused-vars
const [isOpen, open, close, toggle] = useToggle(true, {});
const [monthValue, setMonthValue] = useState('');
const [yearValue, setYearValue] = useState('');
const handleChange = (e) => {
e.preventDefault();
if (e.target.name === 'month') {
setMonthValue(e.target.value);
} else if (e.target.name === 'year') {
setYearValue(e.target.value);
}
};
const handleSubmit = (e) => {
e.preventDefault();
const month = e.target.month.value;
const year = e.target.year.value;
const data = month !== '' && year !== '' ? [{ field_name: 'DOB', field_value: `${year}-${month}` }] : [];
const data = monthValue !== '' && yearValue !== '' ? [{ field_name: 'DOB', field_value: `${yearValue}-${monthValue}` }] : [];
onSubmit('extended_profile', data);
};
@@ -58,7 +68,7 @@ function DOBModal(props) {
if (saveState === 'complete' && isOpen) {
handleComplete();
}
}, [handleComplete, saveState, isOpen]);
}, [handleComplete, saveState, isOpen, monthValue, yearValue]);
return (
<>
@@ -89,7 +99,9 @@ function DOBModal(props) {
<Form.Control
as="select"
name="month"
onChange={handleChange}
>
<option value="">{intl.formatMessage(messages['account.settings.field.dob.month.default'])}</option>
{[...Array(12).keys()].map(month => (
<option key={month + 1} value={month + 1}>{month + 1}</option>
))}
@@ -102,7 +114,9 @@ function DOBModal(props) {
<Form.Control
as="select"
name="year"
onChange={handleChange}
>
<option value="">{intl.formatMessage(messages['account.settings.field.dob.year.default'])}</option>
{YEAR_OF_BIRTH_OPTIONS.map(year => (
<option key={year.value} value={year.value}>{year.label}</option>
))}
@@ -118,11 +132,11 @@ function DOBModal(props) {
</ModalDialog.CloseButton>
<StatefulButton
type="submit"
state={saveState}
state={!(monthValue && yearValue) ? 'unedited' : saveState}
labels={{
default: intl.formatMessage(messages['account.settings.editable.field.action.save']),
}}
disabledStates={[]}
disabledStates={['unedited']}
/>
</ActionRow>
</ModalDialog.Footer>
@@ -131,7 +145,7 @@ function DOBModal(props) {
</ModalDialog>
</>
);
}
};
DOBModal.propTypes = {
saveState: PropTypes.oneOf(['default', 'pending', 'complete', 'error']),

View File

@@ -1,12 +1,11 @@
/* eslint-disable react/jsx-no-useless-fragment */
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { getConfig } from '@edx/frontend-platform';
import classNames from 'classnames';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import {
Button, Input, StatefulButton, ValidationFormGroup,
} from '@edx/paragon';
Button, Form, StatefulButton,
} from '@openedx/paragon';
import { faPencilAlt } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
@@ -20,7 +19,7 @@ import {
import { editableFieldSelector } from './data/selectors';
import CertificatePreference from './certificate-preference/CertificatePreference';
function EditableField(props) {
const EditableField = (props) => {
const {
name,
label,
@@ -28,7 +27,6 @@ function EditableField(props) {
type,
value,
userSuppliedValue,
options,
saveState,
error,
confirmationMessageDefinition,
@@ -45,10 +43,6 @@ function EditableField(props) {
...others
} = props;
const id = `field-${name}`;
let inputOptions = options;
if (getConfig().ENABLE_COPPA_COMPLIANCE && name === 'level_of_education' && options) {
inputOptions = options.filter(option => option.value !== 'el');
}
const handleSubmit = (e) => {
e.preventDefault();
@@ -80,15 +74,6 @@ function EditableField(props) {
}
let finalValue = rawValue;
if (options) {
// Use == instead of === to prevent issues when HTML casts numbers as strings
// eslint-disable-next-line eqeqeq
const selectedOption = options.find(option => option.value == rawValue);
if (selectedOption) {
finalValue = selectedOption.label;
}
}
if (userSuppliedValue) {
finalValue += `: ${userSuppliedValue}`;
}
@@ -112,25 +97,24 @@ function EditableField(props) {
editing: (
<>
<form onSubmit={handleSubmit}>
<ValidationFormGroup
for={id}
invalid={error != null}
invalidMessage={error}
helpText={helpText}
<Form.Group
controlId={id}
isInvalid={error != null}
>
<label className="h6 d-block" htmlFor={id}>{label}</label>
<Input
<Form.Label size="sm" className="h6 d-block" htmlFor={id}>{label}</Form.Label>
<Form.Control
data-hj-suppress
name={name}
id={id}
type={type}
value={value}
onChange={handleChange}
options={inputOptions}
{...others}
/>
<>{others.children}</>
</ValidationFormGroup>
{!!helpText && <Form.Text>{helpText}</Form.Text>}
{error != null && <Form.Control.Feedback hasIcon={false}>{error}</Form.Control.Feedback>}
{others.children}
</Form.Group>
<p>
<StatefulButton
type="submit"
@@ -172,14 +156,14 @@ function EditableField(props) {
</Button>
) : null}
</div>
<p data-hj-suppress className={isGrayedOut ? 'grayed-out' : null}>{renderValue(value)}</p>
<p data-hj-suppress className={classNames('text-truncate', { 'grayed-out': isGrayedOut })}>{renderValue(value)}</p>
<p className="small text-muted mt-n2">{renderConfirmationMessage() || helpText}</p>
</div>
),
}}
/>
);
}
};
EditableField.propTypes = {
name: PropTypes.string.isRequired,
@@ -188,10 +172,6 @@ EditableField.propTypes = {
type: PropTypes.string.isRequired,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
userSuppliedValue: PropTypes.string,
options: PropTypes.arrayOf(PropTypes.shape({
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
})),
saveState: PropTypes.oneOf(['default', 'pending', 'complete', 'error']),
error: PropTypes.string,
confirmationMessageDefinition: PropTypes.shape({
@@ -213,7 +193,6 @@ EditableField.propTypes = {
EditableField.defaultProps = {
value: undefined,
options: undefined,
saveState: undefined,
label: undefined,
emptyLabel: undefined,

View File

@@ -0,0 +1,251 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import {
Button, Form, StatefulButton,
} from '@openedx/paragon';
import { faPencilAlt } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import SwitchContent from './SwitchContent';
import messages from './AccountSettingsPage.messages';
import {
openForm,
closeForm,
} from './data/actions';
import { editableFieldSelector } from './data/selectors';
import CertificatePreference from './certificate-preference/CertificatePreference';
const EditableSelectField = (props) => {
const {
name,
label,
emptyLabel,
type,
value,
userSuppliedValue,
options,
saveState,
error,
confirmationMessageDefinition,
confirmationValue,
helpText,
onEdit,
onCancel,
onSubmit,
onChange,
isEditing,
isEditable,
isGrayedOut,
intl,
...others
} = props;
const id = `field-${name}`;
const handleSubmit = (e) => {
e.preventDefault();
onSubmit(name, new FormData(e.target).get(name));
};
const handleChange = (e) => {
onChange(name, e.target.value);
};
const handleEdit = () => {
onEdit(name);
};
const handleCancel = () => {
onCancel(name);
};
const renderEmptyLabel = () => {
if (isEditable) {
return <Button variant="link" onClick={handleEdit} className="p-0">{emptyLabel}</Button>;
}
return <span className="text-muted">{emptyLabel}</span>;
};
const renderValue = (rawValue) => {
if (!rawValue) {
return renderEmptyLabel();
}
let finalValue = rawValue;
if (options) {
// Use == instead of === to prevent issues when HTML casts numbers as strings
// eslint-disable-next-line eqeqeq
const selectedOption = options.find(option => option.value == rawValue);
if (selectedOption) {
finalValue = selectedOption.label;
}
}
if (userSuppliedValue) {
finalValue += `: ${userSuppliedValue}`;
}
return finalValue;
};
const renderConfirmationMessage = () => {
if (!confirmationMessageDefinition || !confirmationValue) {
return null;
}
return intl.formatMessage(confirmationMessageDefinition, {
value: confirmationValue,
});
};
const selectOptions = options.map((option) => {
if (option.group) {
// If the option has a 'group' property, it represents an element with sub-options.
return (
<optgroup label={option.label} key={option.label}>
{option.group.map((subOption) => (
<option
value={subOption.value}
key={`${subOption.value}-${subOption.label}`}
>
{subOption.label}
</option>
))}
</optgroup>
);
}
return (
<option value={option.value} key={`${option.value}-${option.label}`}>
{option.label}
</option>
);
});
return (
<SwitchContent
expression={isEditing ? 'editing' : 'default'}
cases={{
editing: (
<>
<form onSubmit={handleSubmit}>
<Form.Group
controlId={id}
isInvalid={error != null}
>
<Form.Label size="sm" className="h6 d-block" htmlFor={id}>{label}</Form.Label>
<Form.Control
data-hj-suppress
name={name}
id={id}
type={type}
as={type}
value={value}
onChange={handleChange}
{...others}
>
{options.length > 0 && selectOptions}
</Form.Control>
{!!helpText && <Form.Text>{helpText}</Form.Text>}
{error != null && <Form.Control.Feedback>{error}</Form.Control.Feedback>}
{others.children}
</Form.Group>
<p>
<StatefulButton
type="submit"
className="mr-2"
state={saveState}
labels={{
default: intl.formatMessage(messages['account.settings.editable.field.action.save']),
}}
onClick={(e) => {
// Swallow clicks if the state is pending.
// We do this instead of disabling the button to prevent
// it from losing focus (disabled elements cannot have focus).
// Disabling it would causes upstream issues in focus management.
// Swallowing the onSubmit event on the form would be better, but
// we would have to add that logic for every field given our
// current structure of the application.
if (saveState === 'pending') { e.preventDefault(); }
}}
disabledStates={[]}
/>
<Button
variant="outline-primary"
onClick={handleCancel}
>
{intl.formatMessage(messages['account.settings.editable.field.action.cancel'])}
</Button>
</p>
</form>
{['name', 'verified_name'].includes(name) && <CertificatePreference fieldName={name} />}
</>
),
default: (
<div className="form-group">
<div className="d-flex align-items-start">
<h6 aria-level="3">{label}</h6>
{isEditable ? (
<Button variant="link" onClick={handleEdit} className="ml-3">
<FontAwesomeIcon className="mr-1" icon={faPencilAlt} />{intl.formatMessage(messages['account.settings.editable.field.action.edit'])}
</Button>
) : null}
</div>
<p data-hj-suppress className={isGrayedOut ? 'grayed-out' : null}>{renderValue(value)}</p>
<p className="small text-muted mt-n2">{renderConfirmationMessage() || helpText}</p>
</div>
),
}}
/>
);
};
EditableSelectField.propTypes = {
name: PropTypes.string.isRequired,
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.node]),
emptyLabel: PropTypes.node,
type: PropTypes.string.isRequired,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
userSuppliedValue: PropTypes.string,
options: PropTypes.arrayOf(PropTypes.shape({
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
})),
saveState: PropTypes.oneOf(['default', 'pending', 'complete', 'error']),
error: PropTypes.string,
confirmationMessageDefinition: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
description: PropTypes.string,
}),
confirmationValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
helpText: PropTypes.node,
onEdit: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
isEditing: PropTypes.bool,
isEditable: PropTypes.bool,
isGrayedOut: PropTypes.bool,
intl: intlShape.isRequired,
};
EditableSelectField.defaultProps = {
value: undefined,
options: [],
saveState: undefined,
label: undefined,
emptyLabel: undefined,
error: undefined,
confirmationMessageDefinition: undefined,
confirmationValue: undefined,
helpText: undefined,
isEditing: false,
isEditable: true,
isGrayedOut: false,
userSuppliedValue: undefined,
};
export default connect(editableFieldSelector, {
onEdit: openForm,
onCancel: closeForm,
})(injectIntl(EditableSelectField));

View File

@@ -3,8 +3,8 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n';
import {
Button, StatefulButton, Input, ValidationFormGroup,
} from '@edx/paragon';
Button, StatefulButton, Form,
} from '@openedx/paragon';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faExclamationTriangle, faPencilAlt } from '@fortawesome/free-solid-svg-icons';
@@ -18,7 +18,7 @@ import {
} from './data/actions';
import { editableFieldSelector } from './data/selectors';
function EmailField(props) {
const EmailField = (props) => {
const {
name,
label,
@@ -106,14 +106,12 @@ function EmailField(props) {
cases={{
editing: (
<form onSubmit={handleSubmit}>
<ValidationFormGroup
for={id}
invalid={error != null}
invalidMessage={error}
helpText={helpText}
<Form.Group
controlId={id}
isInvalid={error != null}
>
<label className="h6 d-block" htmlFor={id}>{label}</label>
<Input
<Form.Label className="h6 d-block" htmlFor={id}>{label}</Form.Label>
<Form.Control
data-hj-suppress
name={name}
id={id}
@@ -121,7 +119,9 @@ function EmailField(props) {
value={value}
onChange={handleChange}
/>
</ValidationFormGroup>
{!!helpText && <Form.Text>{helpText}</Form.Text>}
{error != null && <Form.Control.Feedback hasIcon={false}>{error}</Form.Control.Feedback>}
</Form.Group>
<p>
<StatefulButton
type="submit"
@@ -169,7 +169,7 @@ function EmailField(props) {
}}
/>
);
}
};
EmailField.propTypes = {
name: PropTypes.string.isRequired,

View File

@@ -1,20 +1,26 @@
import { getConfig } from '@edx/frontend-platform';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { breakpoints, useWindowSize } from '@edx/paragon';
import { breakpoints, useWindowSize, Icon } from '@openedx/paragon';
import { OpenInNew } from '@openedx/paragon/icons';
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';
import { useSelector } from 'react-redux';
import { NavHashLink } from 'react-router-hash-link';
import Scrollspy from 'react-scrollspy';
import { Link } from 'react-router-dom';
import messages from './AccountSettingsPage.messages';
import { selectShowPreferences } from '../notification-preferences/data/selectors';
function JumpNav({
const JumpNav = ({
intl,
displayDemographicsLink,
}) {
}) => {
const stickToTop = useWindowSize().width > breakpoints.small.minWidth;
const showPreferences = useSelector(selectShowPreferences());
return (
<div className={classNames('jump-nav', { 'jump-nav-sm position-sticky pt-3': stickToTop })}>
<div className={classNames('jump-nav px-2.25', { 'jump-nav-sm position-sticky pt-3': stickToTop })}>
<Scrollspy
items={[
'basic-information',
@@ -61,15 +67,33 @@ function JumpNav({
{intl.formatMessage(messages['account.settings.section.linked.accounts'])}
</NavHashLink>
</li>
<li>
<NavHashLink to="#delete-account">
{intl.formatMessage(messages['account.settings.jump.nav.delete.account'])}
</NavHashLink>
</li>
{getConfig().ENABLE_ACCOUNT_DELETION
&& (
<li>
<NavHashLink to="#delete-account">
{intl.formatMessage(messages['account.settings.jump.nav.delete.account'])}
</NavHashLink>
</li>
)}
</Scrollspy>
{showPreferences && (
<>
<hr />
<Scrollspy
className="list-unstyled"
>
<li>
<Link to="/notifications" target="_blank" rel="noopener noreferrer">
<span>{intl.formatMessage(messages['notification.preferences.notifications.label'])}</span>
<Icon className="d-inline-block align-bottom ml-1" src={OpenInNew} />
</Link>
</li>
</Scrollspy>
</>
)}
</div>
);
}
};
JumpNav.propTypes = {
intl: intlShape.isRequired,

View File

@@ -1,16 +1,19 @@
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="error.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"
data-testid="not-found-page"
>
<p className="my-0 py-5 text-muted" style={{ maxWidth: '32em' }}>
<FormattedMessage
id="error.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

@@ -1,9 +1,9 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { Alert } from '@edx/paragon';
import { Alert } from '@openedx/paragon';
export default function OneTimeDismissibleAlert(props) {
const OneTimeDismissibleAlert = (props) => {
const [dismissed, setDismissed] = useState(localStorage.getItem(props.id) !== 'true');
const onClose = () => {
@@ -25,7 +25,7 @@ export default function OneTimeDismissibleAlert(props) {
</p>
</Alert>
);
}
};
OneTimeDismissibleAlert.propTypes = {
id: PropTypes.string.isRequired,
@@ -41,3 +41,5 @@ OneTimeDismissibleAlert.defaultProps = {
header: undefined,
body: undefined,
};
export default OneTimeDismissibleAlert;

View File

@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { TransitionReplace } from '@edx/paragon';
import { TransitionReplace } from '@openedx/paragon';
const onChildExit = (htmlNode) => {
// If the leaving child has focus, take control and redirect it
@@ -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 {
Form,
ModalDialog,
StatefulButton,
} from '@edx/paragon';
} from '@openedx/paragon';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import {
@@ -21,14 +21,14 @@ import { certPreferenceSelector } from '../data/selectors';
import commonMessages from '../AccountSettingsPage.messages';
import messages from './messages';
function CertificatePreference({
const CertificatePreference = ({
intl,
fieldName,
originalFullName,
originalVerifiedName,
saveState,
useVerifiedNameForCerts,
}) {
}) => {
const dispatch = useDispatch();
const [checked, setChecked] = useState(false);
const [modalIsOpen, setModalIsOpen] = useState(false);
@@ -152,7 +152,7 @@ function CertificatePreference({
</ModalDialog>
</>
) : null;
}
};
CertificatePreference.propTypes = {
intl: intlShape.isRequired,

View File

@@ -2,14 +2,13 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import configureStore from 'redux-mock-store';
import {
fireEvent,
render,
screen,
} from '@testing-library/react';
import { createMemoryHistory } from 'history';
import * as auth from '@edx/frontend-platform/auth';
import { IntlProvider, injectIntl } from '@edx/frontend-platform/i18n';
@@ -28,8 +27,6 @@ jest.mock('react-redux', () => ({
jest.mock('@edx/frontend-platform/auth');
jest.mock('../../data/selectors', () => jest.fn().mockImplementation(() => ({ certPreferenceSelector: () => ({}) })));
const history = createMemoryHistory();
const IntlCertificatePreference = injectIntl(CertificatePreference);
const mockStore = configureStore();
@@ -42,7 +39,7 @@ describe('NameChange', () => {
const labelText = 'If checked, this name will appear on your certificates and public-facing records.';
const reduxWrapper = children => (
<Router history={history}>
<Router>
<IntlProvider locale="en">
<Provider store={store}>{children}</Provider>
</IntlProvider>
@@ -154,7 +151,7 @@ describe('NameChange', () => {
const submitButton = screen.getByText('Choose name');
fireEvent.click(submitButton);
expect(mockDispatch).toHaveBeenCalledWith({
payload: { formId, commitValues: false },
payload: { formId, commitValues: false, extendedProfile: {} },
type: 'ACCOUNT_SETTINGS__SAVE_SETTINGS',
});
});

View File

@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`NameChange does not render if there is no verified name 1`] = `
Object {
{
"asFragment": [Function],
"baseElement": <body>
<div />

View File

@@ -1,271 +0,0 @@
import React from 'react';
import { getConfig, getQueryParameters } from '@edx/frontend-platform';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Hyperlink } from '@edx/paragon';
import { faCheck } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import get from 'lodash.get';
import { getAuthenticatedHttpClient, getAuthenticatedUser } from '@edx/frontend-platform/auth';
import PageLoading from '../PageLoading';
import CoachingConsentForm from './CoachingConsentForm';
import messages from './CoachingConsent.messages';
import LogoSVG from '../../logo.svg';
import { fetchSettings } from '../data/actions';
import { coachingConsentPageSelector } from '../data/selectors';
function Logo({ src, alt, ...attributes }) {
return <img src={src} alt={alt} {...attributes} />;
}
function SuccessMessage(props) {
return (
<div className="col-12 col-lg-6 shadow-lg mx-auto mt-4 p-5">
<FontAwesomeIcon className="text-success" icon={faCheck} size="5x" />
<div className="h3">{props.header}</div>
<div>{props.message}</div>
<Hyperlink destination={props.continueUrl} className="d-block p-2 my-3 text-center text-white bg-primary rounded">
{props.continue}
</Hyperlink>
</div>
);
}
function AutoRedirect(props) {
window.location.href = props.redirectUrl;
// eslint-disable-next-line react/jsx-no-useless-fragment
return <></>;
}
const VIEWS = {
NOT_LOADED: 'NOT_LOADED',
LOADED: 'LOADED',
SUCCESS: 'SUCCESS',
SUCCESS_PENDING: 'SUCCESS_PENDING',
DECLINED: 'DECLINED',
DECLINE_PENDING: 'DECLINE_PENDING',
};
class CoachingConsent extends React.Component {
constructor(props, context) {
super(props, context);
// Used to redirect back to the courseware.
const nextUrl = this.sanitizeForwardingUrl(getQueryParameters().next);
this.state = {
redirectUrl: nextUrl || `${getConfig().LMS_BASE_URL}/dashboard/`,
formErrors: {},
formSubmitted: false,
declineSubmitted: false,
submissionSuccess: false,
};
this.handleSubmit = this.handleSubmit.bind(this);
this.declineCoaching = this.declineCoaching.bind(this);
this.patchUsingCoachingConsentForm = this.patchUsingCoachingConsentForm.bind(this);
}
componentDidMount() {
this.props.fetchSettings();
}
handleSubmit(e) {
e.preventDefault();
const fullName = e.target.fullName.value;
const phoneNumber = e.target.phoneNumber.value;
const body = {
coaching_consent: true,
consent_form_seen: true,
phone_number: phoneNumber,
full_name: fullName,
};
this.setState({
formErrors: {},
formSubmitted: true,
declineSubmitted: false,
}, () => this.patchUsingCoachingConsentForm(body));
}
sanitizeForwardingUrl(url) {
// Redirect to root of MFE if invalid next param is sent
return url && url.startsWith(getConfig().LMS_BASE_URL) ? url : `${getConfig().LMS_BASE_URL}/dashboard/`;
}
async patchUsingCoachingConsentForm(body) {
const { userId } = getAuthenticatedUser();
const requestUrl = `${getConfig().LMS_BASE_URL}/api/coaching/v1/coaching_consent/${userId}/`;
let formErrors = {};
const data = await getAuthenticatedHttpClient()
.patch(requestUrl, body)
.catch((error) => {
if (get(error, 'customAttributes.httpErrorResponseData')) {
formErrors = JSON.parse(error.customAttributes.httpErrorResponseData);
} else {
formErrors = { full_name: 'Something went wrong. Please try again.' };
}
this.setState({
submissionSuccess: false,
formErrors,
formSubmitted: false,
});
});
if (get(data, 'status') === 200) {
this.setState({ submissionSuccess: true });
}
}
declineCoaching(e) {
e.preventDefault();
const body = {
coaching_consent: false,
consent_form_seen: true,
};
this.setState({
formErrors: {},
formSubmitted: false,
declineSubmitted: true,
}, () => this.patchUsingCoachingConsentForm(body));
}
renderView(currentView) {
switch (currentView) {
case VIEWS.NOT_LOADED:
return <PageLoading srMessage="" />;
case VIEWS.LOADED:
return (
<CoachingConsentForm
onSubmit={this.handleSubmit}
declineCoaching={this.declineCoaching}
formErrors={this.state.formErrors}
formValues={this.props.formValues}
redirectUrl={this.state.redirectUrl}
profileDataManager={this.props.profileDataManager}
/>
);
case VIEWS.SUCCESS_PENDING:
return <PageLoading srMessage="Submitting..." />;
case VIEWS.SUCCESS:
return (
<SuccessMessage
continueUrl={this.state.redirectUrl}
header={this.props.intl.formatMessage(messages['account.settings.coaching.consent.success.header'])}
message={this.props.intl.formatMessage(messages['account.settings.coaching.consent.success.message'])}
continue={this.props.intl.formatMessage(messages['account.settings.coaching.consent.success.continue'])}
/>
);
case VIEWS.DECLINE_PENDING:
return <PageLoading srMessage="Redirecting..." />;
case VIEWS.DECLINED:
return <AutoRedirect redirectUrl={this.state.redirectUrl} />;
default:
// eslint-disable-next-line react/jsx-no-useless-fragment
return <></>;
}
}
render() {
const { loaded } = this.props;
const formHasErrors = Object.keys(this.state.formErrors).length > 0;
let currentView = null;
// This amount of logic was making the template very hard to read, so I broke it out into views.
if (!loaded) {
currentView = VIEWS.NOT_LOADED;
} else if (this.state.formSubmitted && !formHasErrors) {
if (this.state.submissionSuccess) {
currentView = VIEWS.SUCCESS;
} else {
currentView = VIEWS.SUCCESS_PENDING;
}
} else if (this.state.declineSubmitted && !formHasErrors) {
if (this.state.submissionSuccess) {
currentView = VIEWS.DECLINED;
} else {
currentView = VIEWS.DECLINE_PENDING;
}
} else {
currentView = VIEWS.LOADED;
}
return (
<main>
<div className="w-100 d-flex justify-content-center align-items-center shadow coaching-header">
<Logo
className="logo"
src={LogoSVG}
alt="Logo"
/>
</div>
{this.renderView(currentView)}
</main>
);
}
}
Logo.defaultProps = {
src: '',
alt: '',
};
Logo.propTypes = {
src: PropTypes.string,
alt: PropTypes.string,
};
SuccessMessage.defaultProps = {
header: '',
message: '',
continueUrl: '',
continue: '',
};
SuccessMessage.propTypes = {
header: PropTypes.string,
message: PropTypes.string,
continueUrl: PropTypes.string,
continue: PropTypes.string,
};
AutoRedirect.defaultProps = {
redirectUrl: '',
};
AutoRedirect.propTypes = {
redirectUrl: PropTypes.string,
};
CoachingConsent.defaultProps = {
loaded: false,
profileDataManager: null,
};
CoachingConsent.propTypes = {
intl: intlShape.isRequired,
loaded: PropTypes.bool,
formValues: PropTypes.shape({
name: PropTypes.string,
phone_number: PropTypes.string,
coaching: PropTypes.shape({
coaching_consent: PropTypes.bool.isRequired,
user: PropTypes.number.isRequired,
eligible_for_coaching: PropTypes.bool.isRequired,
consent_form_seen: PropTypes.bool.isRequired,
}),
}).isRequired,
formErrors: PropTypes.shape({
coaching: PropTypes.shape({}),
}).isRequired,
confirmationValues: PropTypes.shape({
coaching: PropTypes.shape({}),
name: PropTypes.shape({}),
phone_number: PropTypes.shape({}),
}).isRequired,
fetchSettings: PropTypes.func.isRequired,
profileDataManager: PropTypes.string,
};
export default connect(coachingConsentPageSelector, {
fetchSettings,
})(injectIntl(CoachingConsent));

View File

@@ -1,66 +0,0 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
'account.settings.coaching.consent.welcome.header': {
id: 'account.settings.coaching.consent.welcome.header',
defaultMessage: 'Lets get started.',
description: 'The welcome header for consent form.',
},
'account.settings.coaching.consent.welcome.subheader': {
id: 'account.settings.coaching.consent.welcome.subheader',
defaultMessage: "We're here for you from start to finish",
description: 'The welcome subheader for consent form.',
},
'account.settings.coaching.consent.description': {
id: 'account.settings.coaching.consent.description',
defaultMessage: "MicroBachelors programs include coaching that focuses on your career, education, and how you'll achieve results through one-on-one communication with an experienced professional. If youre interested, provide the information below and click “Submit,” and our coaching partner will connect with you via email and/or text message to help you move forward. Terms and conditions apply.*",
description: 'Text describing what Coaching is.',
},
'account.settings.coaching.consent.text-messaging.disclaimer': {
id: 'account.settings.coaching.consent.text-messaging.disclaimer',
defaultMessage: '* Coaching services are included at no additional cost to learners with US phone numbers. Coaching includes recurring text messages. Message and data rates may apply. Text STOP to opt-out.',
description: 'Text describing what Coaching is.',
},
'account.settings.coaching.consent.accept-coaching': {
id: 'account.settings.coaching.consent.accept-coaching',
defaultMessage: 'Sign up for coaching',
description: 'Text to confirm coaching enablement',
},
'account.settings.coaching.consent.decline-coaching': {
id: 'account.settings.coaching.consent.decline-coaching',
defaultMessage: 'I prefer not to be contacted with free coaching services',
description: 'Text to decline coaching enablement',
},
'account.settings.coaching.consent.label.name': {
id: 'account.settings.coaching.consent.label.name',
defaultMessage: 'Please confirm your name',
description: 'Label for name input',
},
'account.settings.coaching.consent.label.phone-number': {
id: 'account.settings.coaching.consent.label.phone-number',
defaultMessage: 'Enter your mobile number',
description: 'Label for mobile phone number input',
},
'account.settings.coaching.consent.success.header': {
id: 'account.settings.coaching.consent.success.header',
defaultMessage: 'Success!',
description: 'Heading announcing that submission succeeded',
},
'account.settings.coaching.consent.success.message': {
id: 'account.settings.coaching.consent.success.message',
defaultMessage: "You're signed up for coaching. You can expect a message via email or SMS in the coming days.",
description: 'Text announcing that you have signed up and will receive texts',
},
'account.settings.coaching.consent.success.continue': {
id: 'account.settings.coaching.consent.success.continue',
defaultMessage: 'Start my course',
description: 'Text that the user will be sent back to the courseware',
},
'account.settings.coaching.managed.support': {
id: 'account.settings.coaching.managed.support',
defaultMessage: 'support',
description: 'website support',
},
});
export default messages;

View File

@@ -1,135 +0,0 @@
import React from 'react';
import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n';
import { Input, Button, Hyperlink } from '@edx/paragon';
import PropTypes from 'prop-types';
import Alert from '../Alert';
import messages from './CoachingConsent.messages';
function ErrorMessage(props) {
return <div className="alert-warning mb-2">{props.message}</div>;
}
function ManagedProfileAlert({ profileDataManager }) {
return (
<Alert className="alert alert-primary" role="alert">
<FormattedMessage
id="account.settings.coaching.managed.alert"
defaultMessage="Your name is managed by {managerTitle}. Contact your administrator for help."
description="Alert message informing the user their account data is managed by a third party"
values={{
managerTitle: <b>{profileDataManager}</b>,
}}
/>
</Alert>
);
}
function CoachingForm(props) {
return (
<div className="col-12 col-md-6 col-xl-5 mx-auto mt-4 p-5 shadow-lg">
<h2 className="h2">
{props.intl.formatMessage(messages['account.settings.coaching.consent.welcome.header'])}
</h2>
<p>{props.intl.formatMessage(messages['account.settings.coaching.consent.description'])}</p>
<div>
<form onSubmit={props.onSubmit}>
<div className="py-3">
{!!props.profileDataManager && (
<ManagedProfileAlert profileDataManager={props.profileDataManager} />
)}
<ErrorMessage message={props.formErrors.full_name} />
<label className="h6" htmlFor="fullName">
{props.intl.formatMessage(messages['account.settings.coaching.consent.label.name'])}
</label>
<Input
type="text"
name="full-name"
id="fullName"
disabled={!!props.profileDataManager}
defaultValue={props.formValues.name}
/>
</div>
<div className="py-3">
<ErrorMessage message={props.formErrors.phone_number} />
<label className="h6" htmlFor="phoneNumber">
{props.intl.formatMessage(messages['account.settings.coaching.consent.label.phone-number'])}
</label>
<Input
type="text"
name="phone_number"
id="phoneNumber"
defaultValue={props.formValues.phone_number}
/>
</div>
<div className=" py-3">
<p className="small font-italic">
{props.intl.formatMessage(messages['account.settings.coaching.consent.text-messaging.disclaimer'])}
</p>
</div>
<ErrorMessage message={props.formErrors.coaching} />
<div className="d-flex flex-column align-items-center">
<Button variant="outline-primary" className="w-100" type="submit">
{props.intl.formatMessage(messages['account.settings.coaching.consent.accept-coaching'])}
</Button>
</div>
<div className="mt-3">
<Hyperlink
className="mt-3 text-dark btn-link small"
destination={props.redirectUrl}
onClick={props.declineCoaching}
>
{props.intl.formatMessage(messages['account.settings.coaching.consent.decline-coaching'])}
</Hyperlink>
</div>
</form>
</div>
</div>
);
}
CoachingForm.defaultProps = {
formErrors: {
coaching: '',
name: '',
phone_number: '',
},
};
CoachingForm.propTypes = {
intl: intlShape.isRequired,
onSubmit: PropTypes.func.isRequired,
declineCoaching: PropTypes.func.isRequired,
formValues: PropTypes.shape({
name: PropTypes.string,
phone_number: PropTypes.string,
coaching: PropTypes.shape({
coaching_consent: PropTypes.bool.isRequired,
user: PropTypes.number.isRequired,
eligible_for_coaching: PropTypes.bool.isRequired,
consent_form_seen: PropTypes.bool.isRequired,
}),
}).isRequired,
formErrors: PropTypes.shape({
coaching: PropTypes.string,
full_name: PropTypes.string,
phone_number: PropTypes.string,
}),
redirectUrl: PropTypes.string.isRequired,
profileDataManager: PropTypes.string.isRequired,
};
ErrorMessage.defaultProps = {
message: '',
};
ErrorMessage.propTypes = {
message: PropTypes.string,
};
ManagedProfileAlert.propTypes = {
profileDataManager: PropTypes.string.isRequired,
};
export default injectIntl(CoachingForm);

View File

@@ -1,101 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { ValidationFormGroup, Input } from '@edx/paragon';
import messages from './CoachingToggle.messages';
import { editableFieldSelector } from '../data/selectors';
import { saveSettings, updateDraft, saveMultipleSettings } from '../data/actions';
import EditableField from '../EditableField';
function CoachingToggle(props) {
return (
<>
<EditableField
name="phone_number"
type="text"
value={props.phone_number}
label={props.intl.formatMessage(messages['account.settings.field.phone_number'])}
emptyLabel={props.intl.formatMessage(messages['account.settings.field.phone_number.empty'])}
onChange={props.updateDraft}
onSubmit={() => {
const { coaching } = props;
if (coaching.coaching_consent === true) {
return props.saveMultipleSettings([
{
formId: 'coaching',
commitValues: {
...coaching,
phone_number: props.phone_number,
},
},
{
formId: 'phone_number',
commitValues: props.phone_number,
},
], 'phone_number');
}
return props.saveSettings('phone_number', props.phone_number);
}}
/>
<ValidationFormGroup
for="coachingConsent"
helpText={props.intl.formatMessage(messages['account.settings.field.coaching_consent.tooltip'])}
invalid={!!props.error}
invalidMessage={props.intl.formatMessage(messages['account.settings.field.coaching_consent.error'])}
className="custom-control custom-switch"
>
<Input
name={props.name}
className="custom-control-input"
disabled={props.saveState === 'pending'}
type="checkbox"
id="coachingConsent"
checked={props.coaching.coaching_consent}
value={props.coaching.coaching_consent}
onChange={async (e) => {
const { name } = e.target;
// eslint-disable-next-line camelcase
const { user, eligible_for_coaching } = props.coaching;
const value = {
user,
// eslint-disable-next-line camelcase
eligible_for_coaching,
coaching_consent: e.target.checked,
};
props.saveSettings(name, value);
}}
/>
<label className="custom-control-label" htmlFor="coachingConsent">{props.intl.formatMessage(messages['account.settings.field.coaching_consent'])}</label>
</ValidationFormGroup>
</>
);
}
CoachingToggle.defaultProps = {
phone_number: '',
error: '',
saveState: undefined,
};
CoachingToggle.propTypes = {
name: PropTypes.string.isRequired,
error: PropTypes.string,
coaching: PropTypes.shape({
coaching_consent: PropTypes.bool.isRequired,
user: PropTypes.number.isRequired,
eligible_for_coaching: PropTypes.bool.isRequired,
}).isRequired,
saveState: PropTypes.oneOf(['default', 'pending', 'complete', 'error']),
saveSettings: PropTypes.func.isRequired,
saveMultipleSettings: PropTypes.func.isRequired,
updateDraft: PropTypes.func.isRequired,
intl: intlShape.isRequired,
phone_number: PropTypes.string,
};
export default connect(editableFieldSelector, {
saveSettings,
updateDraft,
saveMultipleSettings,
})(injectIntl(CoachingToggle));

View File

@@ -1,31 +0,0 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
'account.settings.field.phone_number': {
id: 'account.settings.field.phone_number',
defaultMessage: 'Phone Number',
description: 'The label for a phone numbers setting in the user profile',
},
'account.settings.field.phone_number.empty': {
id: 'account.settings.field.phone_number.empty',
defaultMessage: 'Add a phone number',
description: 'placeholder for a profiles empty phone number field',
},
'account.settings.field.coaching_consent': {
id: 'account.settings.field.coaching_consent',
defaultMessage: 'Coaching consent',
description: 'The label for the coaching consent setting in the user profile',
},
'account.settings.field.coaching_consent.tooltip': {
id: 'account.settings.field.coaching_consent.tooltip',
defaultMessage: 'MicroBachelors programs include text message based coaching that helps you pair educational experiences with your career goals through one-on-one advice. Coaching services are included at no additional cost, and are available to learners with U.S. mobile phone numbers. Standard messaging rates apply. Text STOP at anytime to opt-out of messages.',
description: 'A tooltip explaining what coaching is and who it is for',
},
'account.settings.field.coaching_consent.error': {
id: 'account.settings.field.coaching_consent.error',
defaultMessage: 'A valid US phone number is required to opt into coaching',
description: 'An error message that displays when a user attempts to consent to coaching without first providing a phone number in their profile',
},
});
export default messages;

View File

@@ -1,51 +0,0 @@
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { getConfig } from '@edx/frontend-platform';
import get from 'lodash.get';
/**
* get all settings related to the coaching plugin. Settings used
* by Microbachelors students.
* @param {Number} userId users are identified in the api by LMS id
*/
export async function getCoachingPreferences(userId) {
let data = {};
try {
({ data } = await getAuthenticatedHttpClient()
.get(`${getConfig().LMS_BASE_URL}/api/coaching/v1/users/${userId}/`));
} catch (error) {
// If a user isn't active the API call will fail with a lack of credentials.
data = {
coaching_consent: false,
user: userId,
eligible_for_coaching: false,
consent_form_seen: false,
};
}
return data;
}
/**
* patch all of the settings related to coaching.
* @param {Number} userId users are identified in the api by LMS id
* @param {Object} commitValues { coaching }
*/
export async function patchCoachingPreferences(userId, commitValues) {
const requestUrl = `${getConfig().LMS_BASE_URL}/api/coaching/v1/users/${userId}/`;
const { coaching } = commitValues;
coaching.user = userId;
await getAuthenticatedHttpClient()
.patch(requestUrl, coaching)
.catch((error) => {
const apiError = Object.create(error);
apiError.fieldErrors = JSON.parse(error.customAttributes.httpErrorResponseData);
if (get(apiError, 'fieldErrors.phone_number')) {
// eslint-disable-next-line prefer-destructuring
apiError.fieldErrors.coaching = apiError.fieldErrors.phone_number[0];
delete apiError.fieldErrors.phone_number;
}
throw apiError;
});
return commitValues;
}

View File

@@ -1,103 +0,0 @@
/* eslint-disable no-import-assign */
import React from 'react';
import { Provider } from 'react-redux';
import renderer from 'react-test-renderer';
import { act } from 'react-dom/test-utils';
import configureStore from 'redux-mock-store';
import { IntlProvider, injectIntl } from '@edx/frontend-platform/i18n';
import * as auth from '@edx/frontend-platform/auth';
import CoachingConsent from '../CoachingConsent';
import * as selectors from '../../data/selectors';
jest.mock('@edx/frontend-platform/auth');
const IntlCoachingConsent = injectIntl(CoachingConsent);
jest.mock('../../data/selectors', () => jest.fn().mockImplementation(() => ({ coachingConsentPageSelector: () => ({}) })));
const mockStore = configureStore();
describe('CoachingConsent', () => {
let props = {};
let store = {};
selectors.mockClear();
const reduxWrapper = children => (
<IntlProvider locale="en">
<Provider store={store}>{children}</Provider>
</IntlProvider>
);
beforeEach(() => {
store = mockStore();
props = {
fetchSettings: jest.fn(),
loaded: true,
saveState: undefined,
formValues: {
name: 'edx edx',
phone_number: '1234567890',
coaching: {
coaching_consent: true,
consent_form_seen: false,
eligible_for_coaching: true,
user: 1,
},
},
formErrors: {},
confirmationValues: {},
profileDataManager: '',
intl: {},
};
auth.getAuthenticatedHttpClient = jest.fn(() => ({
patch: async () => ({
data: { status: 200 },
catch: () => {},
}),
}));
auth.getAuthenticatedUser = jest.fn(() => ({ userId: 3 }));
});
it('should render', () => {
const wrapper = renderer.create(reduxWrapper(<IntlCoachingConsent {...props} />)).toJSON();
expect(wrapper).toMatchSnapshot();
});
it('disables name field on enterprise user', () => {
props = {
...props,
profileDataManager: 'test person',
};
const wrapper = renderer.create(reduxWrapper(<IntlCoachingConsent {...props} />)).toJSON();
expect(wrapper).toMatchSnapshot();
});
it('display completed box when successfully submitted', async () => {
const fakeEvent = {
preventDefault: () => {},
target: {
fullName: { value: 'edx edx' },
phoneNumber: { value: '9783028731' },
},
};
const wrapper = renderer.create(
reduxWrapper(<IntlCoachingConsent {...props} />),
{
// bypass the forward-ref. we don't care about focus for this one test
createNodeMock: (element) => {
if (element.type === 'button') {
// mock a focus function
return {
focus: async () => wrapper.root.findByType('form').props.onSubmit(fakeEvent),
};
}
return null;
},
},
);
const form = wrapper.root.findByType('form');
await act(async () => { await form.props.onSubmit(fakeEvent); });
expect(wrapper.toJSON()).toMatchSnapshot();
});
});

View File

@@ -1,276 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CoachingConsent disables name field on enterprise user 1`] = `
<main>
<div
className="w-100 d-flex justify-content-center align-items-center shadow coaching-header"
>
<img
alt="Logo"
className="logo"
src="icon/mock/path"
/>
</div>
<div
className="col-12 col-md-6 col-xl-5 mx-auto mt-4 p-5 shadow-lg"
>
<h2
className="h2"
>
Lets get started.
</h2>
<p>
MicroBachelors programs include coaching that focuses on your career, education, and how you'll achieve results through one-on-one communication with an experienced professional. If youre interested, provide the information below and click “Submit,” and our coaching partner will connect with you via email and/or text message to help you move forward. Terms and conditions apply.*
</p>
<div>
<form
onSubmit={[Function]}
>
<div
className="py-3"
>
<div
className="alert d-flex align-items-start alert alert-primary"
>
<div />
<div>
Your name is managed by
<b>
test person
</b>
. Contact your administrator for help.
</div>
</div>
<div
className="alert-warning mb-2"
>
</div>
<label
className="h6"
htmlFor="fullName"
>
Please confirm your name
</label>
<input
className="form-control"
defaultValue="edx edx"
disabled={true}
id="fullName"
name="full-name"
type="text"
/>
</div>
<div
className="py-3"
>
<div
className="alert-warning mb-2"
>
</div>
<label
className="h6"
htmlFor="phoneNumber"
>
Enter your mobile number
</label>
<input
className="form-control"
defaultValue="1234567890"
id="phoneNumber"
name="phone_number"
type="text"
/>
</div>
<div
className=" py-3"
>
<p
className="small font-italic"
>
* Coaching services are included at no additional cost to learners with US phone numbers. Coaching includes recurring text messages. Message and data rates may apply. Text STOP to opt-out.
</p>
</div>
<div
className="alert-warning mb-2"
>
</div>
<div
className="d-flex flex-column align-items-center"
>
<button
className="w-100 btn btn-outline-primary"
disabled={false}
type="submit"
>
Sign up for coaching
</button>
</div>
<div
className="mt-3"
>
<a
className="pgn__hyperlink default-link standalone-link mt-3 text-dark btn-link small"
href="http://localhost:18000/dashboard/"
onClick={[Function]}
target="_self"
>
I prefer not to be contacted with free coaching services
</a>
</div>
</form>
</div>
</div>
</main>
`;
exports[`CoachingConsent display completed box when successfully submitted 1`] = `
<main>
<div
className="w-100 d-flex justify-content-center align-items-center shadow coaching-header"
>
<img
alt="Logo"
className="logo"
src="icon/mock/path"
/>
</div>
<div>
<div
className="d-flex justify-content-center align-items-center flex-column"
style={
Object {
"height": "50vh",
}
}
>
<div
className="spinner-border text-primary"
role="status"
>
<span
className="sr-only"
>
Submitting...
</span>
</div>
</div>
</div>
</main>
`;
exports[`CoachingConsent should render 1`] = `
<main>
<div
className="w-100 d-flex justify-content-center align-items-center shadow coaching-header"
>
<img
alt="Logo"
className="logo"
src="icon/mock/path"
/>
</div>
<div
className="col-12 col-md-6 col-xl-5 mx-auto mt-4 p-5 shadow-lg"
>
<h2
className="h2"
>
Lets get started.
</h2>
<p>
MicroBachelors programs include coaching that focuses on your career, education, and how you'll achieve results through one-on-one communication with an experienced professional. If youre interested, provide the information below and click “Submit,” and our coaching partner will connect with you via email and/or text message to help you move forward. Terms and conditions apply.*
</p>
<div>
<form
onSubmit={[Function]}
>
<div
className="py-3"
>
<div
className="alert-warning mb-2"
>
</div>
<label
className="h6"
htmlFor="fullName"
>
Please confirm your name
</label>
<input
className="form-control"
defaultValue="edx edx"
disabled={false}
id="fullName"
name="full-name"
type="text"
/>
</div>
<div
className="py-3"
>
<div
className="alert-warning mb-2"
>
</div>
<label
className="h6"
htmlFor="phoneNumber"
>
Enter your mobile number
</label>
<input
className="form-control"
defaultValue="1234567890"
id="phoneNumber"
name="phone_number"
type="text"
/>
</div>
<div
className=" py-3"
>
<p
className="small font-italic"
>
* Coaching services are included at no additional cost to learners with US phone numbers. Coaching includes recurring text messages. Message and data rates may apply. Text STOP to opt-out.
</p>
</div>
<div
className="alert-warning mb-2"
>
</div>
<div
className="d-flex flex-column align-items-center"
>
<button
className="w-100 btn btn-outline-primary"
disabled={false}
type="submit"
>
Sign up for coaching
</button>
</div>
<div
className="mt-3"
>
<a
className="pgn__hyperlink default-link standalone-link mt-3 text-dark btn-link small"
href="http://localhost:18000/dashboard/"
onClick={[Function]}
target="_self"
>
I prefer not to be contacted with free coaching services
</a>
</div>
</form>
</div>
</div>
</main>
`;

View File

@@ -77,9 +77,9 @@ export const beginNameChange = (formId) => ({
});
// SAVE SETTINGS ACTIONS
export const saveSettings = (formId, commitValues) => ({
export const saveSettings = (formId, commitValues, extendedProfile = {}) => ({
type: SAVE_SETTINGS.BASE,
payload: { formId, commitValues },
payload: { formId, commitValues, extendedProfile },
});
export const saveSettingsBegin = () => ({

View File

@@ -25,7 +25,7 @@ export const EDUCATION_LEVELS = [
'jhs',
'el',
'none',
'o',
'other',
];
export const GENDER_OPTIONS = [
@@ -34,6 +34,21 @@ export const GENDER_OPTIONS = [
'm',
'o',
];
export const WORK_EXPERIENCE_OPTIONS = [
'',
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'10+',
];
export const COUNTRY_WITH_STATES = 'US';

View File

@@ -83,8 +83,8 @@ export function* handleSaveSettings(action) {
yield put(saveSettingsBegin());
const { username, userId } = getAuthenticatedUser();
const { commitValues, formId } = action.payload;
const commitData = { [formId]: commitValues };
const { commitValues, formId, extendedProfile } = action.payload;
const commitData = Object.keys(extendedProfile).length > 0 ? extendedProfile : { [formId]: commitValues };
let savedValues = null;
if (formId === 'siteLanguage') {
const previousSiteLanguage = getLocale();

View File

@@ -106,11 +106,6 @@ const isEditingSelector = createSelector(
(name, accountSettings) => accountSettings.openFormId === name,
);
const confirmationValuesSelector = createSelector(
accountSettingsSelector,
accountSettings => accountSettings.confirmationValues,
);
const errorSelector = createSelector(
accountSettingsSelector,
accountSettings => accountSettings.errors,
@@ -161,7 +156,7 @@ function chooseFormValue(draft, committed) {
return draft !== undefined ? draft : committed;
}
const formValuesSelector = createSelector(
export const formValuesSelector = createSelector(
valuesSelector,
draftsSelector,
(values, drafts) => {
@@ -169,6 +164,20 @@ const formValuesSelector = createSelector(
Object.entries(values).forEach(([name, value]) => {
if (typeof value === 'boolean') {
formValues[name] = chooseFormValue(drafts[name], value);
} else if (typeof value === 'object' && name === 'extended_profile' && value !== null) {
const extendedProfile = value.slice();
const draftsKeys = Object.keys(drafts);
if (draftsKeys.length !== 0) {
const draftFieldName = draftsKeys[0];
const index = extendedProfile.findIndex((profile) => profile.field_name === draftFieldName);
if (index !== -1) {
extendedProfile[index] = { field_name: draftFieldName, field_value: drafts[draftFieldName] };
}
}
formValues.extended_profile = [...extendedProfile];
} else {
formValues[name] = chooseFormValue(drafts[name], value) || '';
}
@@ -289,35 +298,6 @@ export const certPreferenceSelector = createSelector(
}),
);
export const coachingConsentPageSelector = createSelector(
accountSettingsSelector,
formValuesSelector,
activeAccountSelector,
profileDataManagerSelector,
saveStateSelector,
confirmationValuesSelector,
errorSelector,
(
accountSettings,
formValues,
activeAccount,
profileDataManager,
saveState,
confirmationValues,
errors,
) => ({
loading: accountSettings.loading,
loaded: accountSettings.loaded,
loadingError: accountSettings.loadingError,
isActive: activeAccount,
profileDataManager,
formValues,
saveState,
confirmationValues,
formErrors: errors,
}),
);
export const demographicsSectionSelector = createSelector(
formValuesSelector,
draftsSelector,

View File

@@ -0,0 +1,72 @@
import { profileDataManagerSelector, formValuesSelector } from './selectors';
const testValue = 'test VALUE';
describe('profileDataManagerSelector', () => {
it('returns the profileDataManager from the state', () => {
const state = {
accountSettings: {
profileDataManager: { testValue },
},
};
const result = profileDataManagerSelector(state);
expect(result).toEqual(state.accountSettings.profileDataManager);
});
it('should correctly select form values', () => {
const state = {
accountSettings: {
values: {
name: 'John Doe',
age: 25,
},
drafts: {
age: 26,
},
verifiedNameHistory: 'test',
confirmationValues: {},
},
};
const result = formValuesSelector(state);
const expected = {
name: 'John Doe',
age: 26,
verified_name: '',
useVerifiedNameForCerts: false,
};
expect(result).toEqual(expected);
});
it('should correctly select form values with extended_profile', () => {
// Mock data with extended_profile field in both values and drafts
const state = {
accountSettings: {
values: {
extended_profile: [
{ field_name: 'test_field', field_value: '5' },
],
},
drafts: { test_field: '6' },
verifiedNameHistory: 'test',
confirmationValues: {},
},
};
const result = formValuesSelector(state);
const expected = {
verified_name: '',
useVerifiedNameForCerts: false,
extended_profile: [ // Draft value should override the committed value
{ field_name: 'test_field', field_value: '6' }, // Value from the committed values
],
};
expect(result).toEqual(expected);
});
});

View File

@@ -8,7 +8,6 @@ import isEmpty from 'lodash.isempty';
import { handleRequestError, unpackFieldErrors } from './utils';
import { getThirdPartyAuthProviders } from '../third-party-auth';
import { postVerifiedNameConfig } from '../certificate-preference/data/service';
import { getCoachingPreferences, patchCoachingPreferences } from '../coaching/data/service';
import { getDemographics, getDemographicsOptions, patchDemographics } from '../demographics/data/service';
import { DEMOGRAPHICS_FIELDS } from '../demographics/data/utils';
@@ -214,7 +213,7 @@ export async function postVerifiedName(data) {
/**
* A single function to GET everything considered a setting.
* Currently encapsulates Account, Preferences, Coaching, ThirdPartyAuth, and Demographics
* Currently encapsulates Account, Preferences, ThirdPartyAuth, and Demographics
*/
export async function getSettings(username, userRoles, userId) {
const [
@@ -223,7 +222,6 @@ export async function getSettings(username, userRoles, userId) {
thirdPartyAuthProviders,
profileDataManager,
timeZones,
coaching,
shouldDisplayDemographicsQuestionsResponse,
demographics,
demographicsOptions,
@@ -233,7 +231,6 @@ export async function getSettings(username, userRoles, userId) {
getThirdPartyAuthProviders(),
getProfileDataManager(username, userRoles),
getTimeZones(),
getConfig().COACHING_ENABLED && getCoachingPreferences(userId),
getConfig().ENABLE_DEMOGRAPHICS_COLLECTION && shouldDisplayDemographicsQuestions(),
getConfig().ENABLE_DEMOGRAPHICS_COLLECTION && getDemographics(userId),
getConfig().ENABLE_DEMOGRAPHICS_COLLECTION && getDemographicsOptions(),
@@ -245,7 +242,6 @@ export async function getSettings(username, userRoles, userId) {
thirdPartyAuthProviders,
profileDataManager,
timeZones,
coaching,
shouldDisplayDemographicsSection: shouldDisplayDemographicsQuestionsResponse,
...demographics,
demographicsOptions,
@@ -254,26 +250,23 @@ export async function getSettings(username, userRoles, userId) {
/**
* A single function to PATCH everything considered a setting.
* Currently encapsulates Account, Preferences, coaching and ThirdPartyAuth
* Currently encapsulates Account, Preferences, ThirdPartyAuth
*/
export async function patchSettings(username, commitValues, userId) {
// Note: time_zone exists in the return value from user/v1/accounts
// but it is always null and won't update. It also exists in
// user/v1/preferences where it does update. This is the one we use.
const preferenceKeys = ['time_zone'];
const coachingKeys = ['coaching'];
const demographicsKeys = DEMOGRAPHICS_FIELDS;
const certificateKeys = ['useVerifiedNameForCerts'];
const isDemographicsKey = (value, key) => key.includes('demographics');
const accountCommitValues = omit(
commitValues,
preferenceKeys,
coachingKeys,
demographicsKeys,
certificateKeys,
);
const preferenceCommitValues = pick(commitValues, preferenceKeys);
const coachingCommitValues = pick(commitValues, coachingKeys);
const demographicsCommitValues = pickBy(commitValues, isDemographicsKey);
const certCommitValues = pick(commitValues, certificateKeys);
const patchRequests = [];
@@ -284,9 +277,6 @@ export async function patchSettings(username, commitValues, userId) {
if (!isEmpty(preferenceCommitValues)) {
patchRequests.push(patchPreferences(username, preferenceCommitValues));
}
if (!isEmpty(coachingCommitValues)) {
patchRequests.push(patchCoachingPreferences(userId, coachingCommitValues));
}
if (!isEmpty(demographicsCommitValues)) {
patchRequests.push(patchDemographics(userId, demographicsCommitValues));
}

View File

@@ -1,8 +1,7 @@
import { put } from 'redux-saga/effects';
import { logError } from '@edx/frontend-platform/logging';
import { history } from '@edx/frontend-platform';
export default function* handleFailure(error, failureAction = null, failureRedirectPath = null) {
export default function* handleFailure(error, navigate, failureAction = null, failureRedirectPath = null) {
if (error.fieldErrors && failureAction !== null) {
yield put(failureAction({ fieldErrors: error.fieldErrors }));
}
@@ -11,6 +10,6 @@ export default function* handleFailure(error, failureAction = null, failureRedir
yield put(failureAction(error.message));
}
if (failureRedirectPath !== null) {
history.push(failureRedirectPath);
navigate(failureRedirectPath);
}
}

View File

@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Hyperlink } from '@edx/paragon';
import { Hyperlink } from '@openedx/paragon';
// Messages
import { getConfig } from '@edx/frontend-platform';
@@ -12,7 +12,7 @@ import messages from './messages';
// Components
import Alert from '../Alert';
function BeforeProceedingBanner(props) {
const BeforeProceedingBanner = (props) => {
const { instructionMessageId, intl, supportArticleUrl } = props;
return (
@@ -25,17 +25,19 @@ function BeforeProceedingBanner(props) {
defaultMessage="Before proceeding, please {actionLink}."
description="Error that appears if you are trying to delete your account, but something about your account needs attention first. The actionLink will be instructions, such as 'unlink your Facebook account'."
values={{
actionLink: (
actionLink: supportArticleUrl ? (
<Hyperlink destination={supportArticleUrl}>
{intl.formatMessage(messages[instructionMessageId])}
</Hyperlink>
) : (
intl.formatMessage(messages[instructionMessageId])
),
siteName: getConfig().SITE_NAME,
}}
/>
</Alert>
);
}
};
BeforeProceedingBanner.propTypes = {
instructionMessageId: PropTypes.string.isRequired,

View File

@@ -0,0 +1,48 @@
import React from 'react';
import ReactDOM from 'react-dom';
import renderer from 'react-test-renderer';
import { IntlProvider, injectIntl, createIntl } from '@edx/frontend-platform/i18n';
ReactDOM.createPortal = node => node;
import BeforeProceedingBanner from './BeforeProceedingBanner'; // eslint-disable-line import/first
const IntlBeforeProceedingBanner = injectIntl(BeforeProceedingBanner);
describe('BeforeProceedingBanner', () => {
it('should match the snapshot if SUPPORT_URL_TO_UNLINK_SOCIAL_MEDIA_ACCOUNT does not have a support link', () => {
const props = {
instructionMessageId: 'account.settings.delete.account.please.unlink',
intl: createIntl({ locale: 'en' }),
supportArticleUrl: '',
};
const tree = renderer
.create((
<IntlProvider locale="en">
<IntlBeforeProceedingBanner
{...props}
/>
</IntlProvider>
))
.toJSON();
expect(tree).toMatchSnapshot();
});
it('should match the snapshot when SUPPORT_URL_TO_UNLINK_SOCIAL_MEDIA_ACCOUNT has a support link', () => {
const props = {
instructionMessageId: 'account.settings.delete.account.please.unlink',
intl: createIntl({ locale: 'en' }),
supportArticleUrl: 'http://test-support.edx',
};
const tree = renderer
.create((
<IntlProvider locale="en">
<IntlBeforeProceedingBanner
{...props}
/>
</IntlProvider>
))
.toJSON();
expect(tree).toMatchSnapshot();
});
});

View File

@@ -2,12 +2,12 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
Button, Input, Modal, ValidationFormGroup,
} from '@edx/paragon';
AlertModal,
Button, Input, ValidationFormGroup, ActionRow,
} from '@openedx/paragon';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { faExclamationCircle, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { getConfig } from '@edx/frontend-platform';
import messages from './messages';
import Alert from '../Alert';
@@ -74,59 +74,58 @@ export class ConfirmationModal extends Component {
: 'account.settings.delete.account.modal.text.2';
return (
<Modal
open={open}
<AlertModal
isOpen={open}
title={intl.formatMessage(messages['account.settings.delete.account.modal.header'])}
body={(
<div>
{this.renderError()}
<Alert
className="alert-warning mt-n2"
icon={<FontAwesomeIcon className="mr-2" icon={faExclamationTriangle} />}
>
<h6>
{intl.formatMessage(
messages['account.settings.delete.account.modal.text.1'],
{ siteName: getConfig().SITE_NAME },
)}
</h6>
<p>
{intl.formatMessage(
messages[deleteAccountModalText2MessageKey],
{ siteName: getConfig().SITE_NAME },
)}
</p>
<p>
<PrintingInstructions />
</p>
</Alert>
<ValidationFormGroup
for={passwordFieldId}
invalid={errorType !== null}
invalidMessage={intl.formatMessage(invalidMessage)}
>
<label className="d-block" htmlFor={passwordFieldId}>
{intl.formatMessage(messages['account.settings.delete.account.modal.enter.password'])}
</label>
<Input
name="password"
id={passwordFieldId}
type="password"
value={password}
onChange={onChange}
/>
</ValidationFormGroup>
</div>
)}
buttons={[
<Button variant="danger" onClick={onSubmit}>
{intl.formatMessage(messages['account.settings.delete.account.modal.confirm.delete'])}
</Button>,
]}
closeText={intl.formatMessage(messages['account.settings.delete.account.modal.confirm.cancel'])}
renderHeaderCloseButton={false}
onClose={onCancel}
/>
footerNode={(
<ActionRow>
<Button variant="link" onClick={onCancel}>Cancel</Button>
<Button variant="danger" onClick={onSubmit}>Yes, Delete</Button>
</ActionRow>
)}
>
<div className="p-3">
{this.renderError()}
<Alert
className="alert-warning mt-n2"
icon={<FontAwesomeIcon className="mr-2" icon={faExclamationTriangle} />}
>
<h6>
{intl.formatMessage(
messages['account.settings.delete.account.modal.text.1'],
{ siteName: getConfig().SITE_NAME },
)}
</h6>
<p>
{intl.formatMessage(
messages[deleteAccountModalText2MessageKey],
{ siteName: getConfig().SITE_NAME },
)}
</p>
<p>
<PrintingInstructions />
</p>
</Alert>
<ValidationFormGroup
for={passwordFieldId}
invalid={errorType !== null}
invalidMessage={intl.formatMessage(invalidMessage)}
>
<label className="d-block" htmlFor={passwordFieldId}>
{intl.formatMessage(messages['account.settings.delete.account.modal.enter.password'])}
</label>
<Input
name="password"
id={passwordFieldId}
type="password"
value={password}
onChange={onChange}
/>
</ValidationFormGroup>
</div>
</AlertModal>
);
}
}

View File

@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { getConfig } from '@edx/frontend-platform';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Button, Hyperlink } from '@edx/paragon';
import { Button, Hyperlink } from '@openedx/paragon';
// Actions
import {
@@ -59,6 +59,7 @@ export class DeleteAccount extends React.Component {
hasLinkedTPA, isVerifiedAccount, status, errorType, intl,
} = this.props;
const canDelete = isVerifiedAccount && !hasLinkedTPA;
const supportArticleUrl = process.env.SUPPORT_URL_TO_UNLINK_SOCIAL_MEDIA_ACCOUNT;
// TODO: We lack a good way of providing custom language for a particular site. This is a hack
// to allow edx.org to fulfill its business requirements.
@@ -122,7 +123,7 @@ export class DeleteAccount extends React.Component {
{hasLinkedTPA ? (
<BeforeProceedingBanner
instructionMessageId="account.settings.delete.account.please.unlink"
supportArticleUrl="https://support.edx.org/hc/en-us/articles/207206067"
supportArticleUrl={supportArticleUrl}
/>
) : null}

View File

@@ -4,10 +4,10 @@ import renderer from 'react-test-renderer';
import { IntlProvider, injectIntl } from '@edx/frontend-platform/i18n';
// Testing the modals separately, they just clutter up the snapshots if included here.
jest.mock('./ConfirmationModal', () => function () {
jest.mock('./ConfirmationModal', () => function ConfirmationModalMock() {
return <></>;
});
jest.mock('./SuccessModal', () => function () {
jest.mock('./SuccessModal', () => function SuccessModalMock() {
return <></>;
});

View File

@@ -1,11 +1,11 @@
import React from 'react';
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Hyperlink } from '@edx/paragon';
import { Hyperlink } from '@openedx/paragon';
import { getConfig } from '@edx/frontend-platform';
import messages from './messages';
function PrintingInstructions(props) {
const PrintingInstructions = (props) => {
const actionLink = (
<Hyperlink
// TODO: What would a generic version of this link look like? Should
@@ -38,7 +38,7 @@ function PrintingInstructions(props) {
values={{ actionLink }}
/>
);
}
};
PrintingInstructions.propTypes = {
intl: intlShape.isRequired,

View File

@@ -1,29 +1,33 @@
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Modal } from '@edx/paragon';
import { ModalLayer, ModalCloseButton } from '@openedx/paragon';
import messages from './messages';
export function SuccessModal(props) {
export const SuccessModal = (props) => {
const { status, intl, onClose } = props;
return (
<Modal
open={status === 'deleted'}
title={intl.formatMessage(messages['account.settings.delete.account.modal.after.header'])}
body={(
<div>
<ModalLayer isOpen={status === 'deleted'} onClose={onClose}>
<div className="mw-sm p-5 bg-white mx-auto my-3">
<h3>
{intl.formatMessage(messages['account.settings.delete.account.modal.after.header'])}
</h3>
<div className="p-3">
<p className="h6">
{intl.formatMessage(messages['account.settings.delete.account.modal.after.text'])}
</p>
</div>
)}
closeText={intl.formatMessage(messages['account.settings.delete.account.modal.after.button'])}
renderHeaderCloseButton={false}
onClose={onClose}
/>
<p>
<ModalCloseButton className="float-right" variant="link">Close</ModalCloseButton>
</p>
</div>
</ModalLayer>
);
}
};
SuccessModal.propTypes = {
status: PropTypes.oneOf(['confirming', 'pending', 'deleted', 'failed']),

View File

@@ -0,0 +1,68 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`BeforeProceedingBanner should match the snapshot if SUPPORT_URL_TO_UNLINK_SOCIAL_MEDIA_ACCOUNT does not have a support link 1`] = `
<div
className="alert d-flex align-items-start alert-warning mt-n2"
>
<div>
<svg
aria-hidden="true"
className="svg-inline--fa fa-exclamation-triangle fa-w-18 mr-2"
data-icon="exclamation-triangle"
data-prefix="fas"
focusable="false"
role="img"
style={{}}
viewBox="0 0 576 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"
fill="currentColor"
style={{}}
/>
</svg>
</div>
<div>
Before proceeding, please unlink all social media accounts.
</div>
</div>
`;
exports[`BeforeProceedingBanner should match the snapshot when SUPPORT_URL_TO_UNLINK_SOCIAL_MEDIA_ACCOUNT has a support link 1`] = `
<div
className="alert d-flex align-items-start alert-warning mt-n2"
>
<div>
<svg
aria-hidden="true"
className="svg-inline--fa fa-exclamation-triangle fa-w-18 mr-2"
data-icon="exclamation-triangle"
data-prefix="fas"
focusable="false"
role="img"
style={{}}
viewBox="0 0 576 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"
fill="currentColor"
style={{}}
/>
</svg>
</div>
<div>
Before proceeding, please
<a
className="pgn__hyperlink default-link standalone-link"
href="http://test-support.edx"
onClick={[Function]}
target="_self"
>
unlink all social media accounts
</a>
.
</div>
</div>
`;

View File

@@ -1,222 +1,68 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ConfirmationModal should match default closed confirmation modal snapshot 1`] = `
Array [
<div
className="fade"
role="presentation"
/>,
<div
className="modal fade"
role="presentation"
>
<div
aria-labelledby="id1"
aria-modal={true}
className=""
role="dialog"
>
<div
data-focus-guard={true}
style={
Object {
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={-1}
/>
<div
data-focus-lock-disabled="disabled"
onBlur={[Function]}
onFocus={[Function]}
onScrollCapture={[Function]}
onTouchMoveCapture={[Function]}
onWheelCapture={[Function]}
>
<div
className="modal-content"
>
<div
className="modal-header"
>
<h2
className="modal-title"
id="id1"
>
Are you sure?
</h2>
</div>
<div
className="modal-body"
>
<div>
<div
className="alert d-flex align-items-start alert-warning mt-n2"
>
<div>
<svg
aria-hidden="true"
className="svg-inline--fa fa-exclamation-triangle fa-w-18 mr-2"
data-icon="exclamation-triangle"
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
viewBox="0 0 576 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"
fill="currentColor"
style={Object {}}
/>
</svg>
</div>
<div>
<h6>
You have selected "Delete My Account". Deletion of your account and personal data is permanent and cannot be undone. localhost will not be able to recover your account or the data that is deleted.
</h6>
<p>
If you proceed, you will be unable to use this account to take courses on localhost.
</p>
<p>
You may also lose access to verified certificates and other program credentials. You can make a copy of these for your records before proceeding with deletion.
</p>
</div>
</div>
<div
className="form-group"
>
<label
className="d-block"
htmlFor="passwordFieldId"
>
If you still wish to continue and delete your account, please enter your account password:
</label>
<input
aria-describedby=""
className="form-control"
id="passwordFieldId"
name="password"
onChange={[MockFunction]}
type="password"
value="fluffy bunnies"
/>
<strong
className="invalid-feedback"
id="passwordFieldId-invalid-feedback"
>
Unable to delete account
</strong>
</div>
</div>
</div>
<div
className="modal-footer"
>
<button
className="btn btn-link"
disabled={false}
onClick={[Function]}
type="button"
>
Cancel
</button>
<button
className="btn btn-danger"
disabled={false}
onClick={[MockFunction]}
type="button"
>
Yes, Delete
</button>
</div>
</div>
</div>
<div
data-focus-guard={true}
style={
Object {
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={-1}
/>
</div>
</div>,
]
`;
exports[`ConfirmationModal should match default closed confirmation modal snapshot 1`] = `null`;
exports[`ConfirmationModal should match empty password confirmation modal snapshot 1`] = `
Array [
[
<div
className="modal-backdrop show"
role="presentation"
data-focus-guard={true}
style={
{
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={0}
/>,
<div
className="modal show d-block"
role="presentation"
className="pgn__modal-layer"
data-focus-lock-disabled={false}
onBlur={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onScrollCapture={[Function]}
onTouchMoveCapture={[Function]}
onTouchStart={[Function]}
onWheelCapture={[Function]}
>
<div
aria-labelledby="id3"
aria-modal={true}
className="modal-dialog"
role="dialog"
className="pgn__modal-content-container"
>
<div
data-focus-guard={true}
style={
Object {
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={0}
className="pgn__modal-backdrop"
data-testid="modal-backdrop"
onClick={[MockFunction]}
onKeyDown={[MockFunction]}
/>
<div
data-focus-lock-disabled={false}
onBlur={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onScrollCapture={[Function]}
onTouchMoveCapture={[Function]}
onTouchStart={[Function]}
onWheelCapture={[Function]}
aria-label="Are you sure?"
className="pgn__modal pgn__modal-md pgn__modal-default pgn__alert-modal"
role="dialog"
>
<div
className="modal-content"
className="pgn__modal-header"
>
<div
className="modal-header"
<h2
className="pgn__modal-title"
>
<h2
className="modal-title"
id="id3"
Are you sure?
</h2>
</div>
<div
className="pgn__modal-body pgn__modal-body-scroll-top pgn__modal-body-scroll-bottom"
>
<div />
<div
className="pgn__modal-body-content"
>
<div
className="p-3"
>
Are you sure?
</h2>
</div>
<div
className="modal-body"
>
<div>
<div
className="alert d-flex align-items-start alert-danger mt-n2"
>
@@ -228,14 +74,14 @@ Array [
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
</div>
@@ -261,14 +107,14 @@ Array [
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 576 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
</div>
@@ -286,6 +132,7 @@ Array [
</div>
<div
className="form-group"
data-testid="validation-form-group"
>
<label
className="d-block"
@@ -311,13 +158,18 @@ Array [
</div>
</div>
</div>
<div />
</div>
<div
className="pgn__modal-footer"
>
<div
className="modal-footer"
className="pgn__action-row"
>
<button
className="btn btn-link"
disabled={false}
onClick={[Function]}
onClick={[MockFunction]}
type="button"
>
Cancel
@@ -333,82 +185,85 @@ Array [
</div>
</div>
</div>
<div
data-focus-guard={true}
style={
Object {
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={0}
/>
</div>
</div>,
<div
data-focus-guard={true}
style={
{
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={0}
/>,
]
`;
exports[`ConfirmationModal should match open confirmation modal snapshot 1`] = `
Array [
[
<div
className="modal-backdrop show"
role="presentation"
data-focus-guard={true}
style={
{
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={-1}
/>,
<div
className="modal show d-block"
role="presentation"
className="pgn__modal-layer"
data-focus-lock-disabled="disabled"
onBlur={[Function]}
onFocus={[Function]}
onScrollCapture={[Function]}
onTouchMoveCapture={[Function]}
onWheelCapture={[Function]}
>
<div
aria-labelledby="id2"
aria-modal={true}
className="modal-dialog"
role="dialog"
className="pgn__modal-content-container"
>
<div
data-focus-guard={true}
style={
Object {
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={-1}
className="pgn__modal-backdrop"
data-testid="modal-backdrop"
onClick={[MockFunction]}
onKeyDown={[MockFunction]}
/>
<div
data-focus-lock-disabled="disabled"
onBlur={[Function]}
onFocus={[Function]}
onScrollCapture={[Function]}
onTouchMoveCapture={[Function]}
onWheelCapture={[Function]}
aria-label="Are you sure?"
className="pgn__modal pgn__modal-md pgn__modal-default pgn__alert-modal"
role="dialog"
>
<div
className="modal-content"
className="pgn__modal-header"
>
<div
className="modal-header"
<h2
className="pgn__modal-title"
>
<h2
className="modal-title"
id="id2"
Are you sure?
</h2>
</div>
<div
className="pgn__modal-body pgn__modal-body-scroll-top pgn__modal-body-scroll-bottom"
>
<div />
<div
className="pgn__modal-body-content"
>
<div
className="p-3"
>
Are you sure?
</h2>
</div>
<div
className="modal-body"
>
<div>
<div
className="alert d-flex align-items-start alert-warning mt-n2"
>
@@ -420,14 +275,14 @@ Array [
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 576 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
</div>
@@ -445,6 +300,7 @@ Array [
</div>
<div
className="form-group"
data-testid="validation-form-group"
>
<label
className="d-block"
@@ -470,13 +326,18 @@ Array [
</div>
</div>
</div>
<div />
</div>
<div
className="pgn__modal-footer"
>
<div
className="modal-footer"
className="pgn__action-row"
>
<button
className="btn btn-link"
disabled={false}
onClick={[Function]}
onClick={[MockFunction]}
type="button"
>
Cancel
@@ -492,22 +353,22 @@ Array [
</div>
</div>
</div>
<div
data-focus-guard={true}
style={
Object {
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={-1}
/>
</div>
</div>,
<div
data-focus-guard={true}
style={
{
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={-1}
/>,
]
`;

View File

@@ -102,14 +102,14 @@ exports[`DeleteAccount should match unverified account section snapshot 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 576 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
</div>
@@ -184,14 +184,14 @@ exports[`DeleteAccount should match unverified account section snapshot 2`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 576 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
</div>

View File

@@ -1,486 +1,90 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`SuccessModal should match default closed success modal snapshot 1`] = `
Array [
<div
className="fade"
role="presentation"
/>,
<div
className="modal fade"
role="presentation"
>
<div
aria-labelledby="id1"
aria-modal={true}
className=""
role="dialog"
>
<div
data-focus-guard={true}
style={
Object {
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={-1}
/>
<div
data-focus-lock-disabled="disabled"
onBlur={[Function]}
onFocus={[Function]}
onScrollCapture={[Function]}
onTouchMoveCapture={[Function]}
onWheelCapture={[Function]}
>
<div
className="modal-content"
>
<div
className="modal-header"
>
<h2
className="modal-title"
id="id1"
>
We're sorry to see you go! Your account will be deleted shortly.
</h2>
</div>
<div
className="modal-body"
>
<div>
<p
className="h6"
>
Account deletion, including removal from email lists, may take a few weeks to fully process through our system. If you want to opt-out of emails before then, please unsubscribe from the footer of any email.
</p>
</div>
</div>
<div
className="modal-footer"
>
<button
className="btn btn-link"
disabled={false}
onClick={[Function]}
type="button"
>
Close
</button>
</div>
</div>
</div>
<div
data-focus-guard={true}
style={
Object {
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={-1}
/>
</div>
</div>,
]
`;
exports[`SuccessModal should match default closed success modal snapshot 1`] = `null`;
exports[`SuccessModal should match default closed success modal snapshot 2`] = `
Array [
<div
className="fade"
role="presentation"
/>,
<div
className="modal fade"
role="presentation"
>
<div
aria-labelledby="id2"
aria-modal={true}
className=""
role="dialog"
>
<div
data-focus-guard={true}
style={
Object {
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={-1}
/>
<div
data-focus-lock-disabled="disabled"
onBlur={[Function]}
onFocus={[Function]}
onScrollCapture={[Function]}
onTouchMoveCapture={[Function]}
onWheelCapture={[Function]}
>
<div
className="modal-content"
>
<div
className="modal-header"
>
<h2
className="modal-title"
id="id2"
>
We're sorry to see you go! Your account will be deleted shortly.
</h2>
</div>
<div
className="modal-body"
>
<div>
<p
className="h6"
>
Account deletion, including removal from email lists, may take a few weeks to fully process through our system. If you want to opt-out of emails before then, please unsubscribe from the footer of any email.
</p>
</div>
</div>
<div
className="modal-footer"
>
<button
className="btn btn-link"
disabled={false}
onClick={[Function]}
type="button"
>
Close
</button>
</div>
</div>
</div>
<div
data-focus-guard={true}
style={
Object {
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={-1}
/>
</div>
</div>,
]
`;
exports[`SuccessModal should match default closed success modal snapshot 2`] = `null`;
exports[`SuccessModal should match default closed success modal snapshot 3`] = `
Array [
<div
className="fade"
role="presentation"
/>,
<div
className="modal fade"
role="presentation"
>
<div
aria-labelledby="id3"
aria-modal={true}
className=""
role="dialog"
>
<div
data-focus-guard={true}
style={
Object {
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={-1}
/>
<div
data-focus-lock-disabled="disabled"
onBlur={[Function]}
onFocus={[Function]}
onScrollCapture={[Function]}
onTouchMoveCapture={[Function]}
onWheelCapture={[Function]}
>
<div
className="modal-content"
>
<div
className="modal-header"
>
<h2
className="modal-title"
id="id3"
>
We're sorry to see you go! Your account will be deleted shortly.
</h2>
</div>
<div
className="modal-body"
>
<div>
<p
className="h6"
>
Account deletion, including removal from email lists, may take a few weeks to fully process through our system. If you want to opt-out of emails before then, please unsubscribe from the footer of any email.
</p>
</div>
</div>
<div
className="modal-footer"
>
<button
className="btn btn-link"
disabled={false}
onClick={[Function]}
type="button"
>
Close
</button>
</div>
</div>
</div>
<div
data-focus-guard={true}
style={
Object {
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={-1}
/>
</div>
</div>,
]
`;
exports[`SuccessModal should match default closed success modal snapshot 3`] = `null`;
exports[`SuccessModal should match default closed success modal snapshot 4`] = `
Array [
<div
className="fade"
role="presentation"
/>,
<div
className="modal fade"
role="presentation"
>
<div
aria-labelledby="id4"
aria-modal={true}
className=""
role="dialog"
>
<div
data-focus-guard={true}
style={
Object {
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={-1}
/>
<div
data-focus-lock-disabled="disabled"
onBlur={[Function]}
onFocus={[Function]}
onScrollCapture={[Function]}
onTouchMoveCapture={[Function]}
onWheelCapture={[Function]}
>
<div
className="modal-content"
>
<div
className="modal-header"
>
<h2
className="modal-title"
id="id4"
>
We're sorry to see you go! Your account will be deleted shortly.
</h2>
</div>
<div
className="modal-body"
>
<div>
<p
className="h6"
>
Account deletion, including removal from email lists, may take a few weeks to fully process through our system. If you want to opt-out of emails before then, please unsubscribe from the footer of any email.
</p>
</div>
</div>
<div
className="modal-footer"
>
<button
className="btn btn-link"
disabled={false}
onClick={[Function]}
type="button"
>
Close
</button>
</div>
</div>
</div>
<div
data-focus-guard={true}
style={
Object {
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={-1}
/>
</div>
</div>,
]
`;
exports[`SuccessModal should match default closed success modal snapshot 4`] = `null`;
exports[`SuccessModal should match open success modal snapshot 1`] = `
Array [
[
<div
className="modal-backdrop show"
role="presentation"
data-focus-guard={true}
style={
{
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={-1}
/>,
<div
className="modal show d-block"
role="presentation"
className="pgn__modal-layer"
data-focus-lock-disabled="disabled"
onBlur={[Function]}
onFocus={[Function]}
onScrollCapture={[Function]}
onTouchMoveCapture={[Function]}
onWheelCapture={[Function]}
>
<div
aria-labelledby="id5"
aria-modal={true}
className="modal-dialog"
role="dialog"
className="pgn__modal-content-container"
>
<div
data-focus-guard={true}
style={
Object {
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={-1}
className="pgn__modal-backdrop"
data-testid="modal-backdrop"
onClick={[MockFunction]}
onKeyDown={[MockFunction]}
/>
<div
data-focus-lock-disabled="disabled"
onBlur={[Function]}
onFocus={[Function]}
onScrollCapture={[Function]}
onTouchMoveCapture={[Function]}
onWheelCapture={[Function]}
className="mw-sm p-5 bg-white mx-auto my-3"
>
<h3>
We're sorry to see you go! Your account will be deleted shortly.
</h3>
<div
className="modal-content"
className="p-3"
>
<div
className="modal-header"
<p
className="h6"
>
<h2
className="modal-title"
id="id5"
>
We're sorry to see you go! Your account will be deleted shortly.
</h2>
</div>
<div
className="modal-body"
>
<div>
<p
className="h6"
>
Account deletion, including removal from email lists, may take a few weeks to fully process through our system. If you want to opt-out of emails before then, please unsubscribe from the footer of any email.
</p>
</div>
</div>
<div
className="modal-footer"
>
<button
className="btn btn-link"
disabled={false}
onClick={[Function]}
type="button"
>
Close
</button>
</div>
Account deletion, including removal from email lists, may take a few weeks to fully process through our system. If you want to opt-out of emails before then, please unsubscribe from the footer of any email.
</p>
</div>
<p>
<button
className="pgn__modal-close-button float-right btn btn-link"
disabled={false}
onClick={[Function]}
type="button"
>
Close
</button>
</p>
</div>
<div
data-focus-guard={true}
style={
Object {
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={-1}
/>
</div>
</div>,
<div
data-focus-guard={true}
style={
{
"height": "0px",
"left": "1px",
"overflow": "hidden",
"padding": 0,
"position": "fixed",
"top": "1px",
"width": "1px",
}
}
tabIndex={-1}
/>,
]
`;

View File

@@ -1,9 +1,9 @@
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { CheckBox } from '@edx/paragon';
import { Form } from '@openedx/paragon';
import { DECLINED } from '../data/constants';
function Checkboxes(props) {
const Checkboxes = (props) => {
const {
id,
options,
@@ -40,16 +40,17 @@ function Checkboxes(props) {
const isChecked = selected.includes(option.value);
return (
<div key={option.value} className="checkboxOption">
<CheckBox
<Form.Checkbox
type="checkbox"
id={option.value}
name={option.value}
value={option.value}
checked={isChecked}
autoFocus={isFirst}
label={option.label}
onChange={(value) => handleToggle(value, option.value)}
/>
onChange={(event) => handleToggle(event.target.checked, option.value)}
>
{option.label}
</Form.Checkbox>
</div>
);
});
@@ -59,7 +60,7 @@ function Checkboxes(props) {
{renderCheckboxes()}
</div>
);
}
};
Checkboxes.propTypes = {
id: PropTypes.string.isRequired,

View File

@@ -5,7 +5,7 @@ import {
intlShape,
} from '@edx/frontend-platform/i18n';
import { Hyperlink, Input } from '@edx/paragon';
import { Hyperlink, Form } from '@openedx/paragon';
import PropTypes from 'prop-types';
import React from 'react';
import { connect } from 'react-redux';
@@ -13,7 +13,7 @@ import get from 'lodash.get';
import isEmpty from 'lodash.isempty';
import memoize from 'memoize-one';
import { demographicsSectionSelector } from '../data/selectors';
import EditableField from '../EditableField';
import EditableSelectField from '../EditableSelectField';
import Checkboxes from './Checkboxes';
import Alert from '../Alert';
import { saveMultipleSettings, updateDraft } from '../data/actions';
@@ -188,7 +188,7 @@ class DemographicsSection extends React.Component {
*/}
{this.hasRetrievedDemographicsOptions() && (
<div id="demographics-fields">
<EditableField
<EditableSelectField
name="demographics_gender"
type="select"
value={this.props.formValues.demographics_gender}
@@ -199,7 +199,7 @@ class DemographicsSection extends React.Component {
{...editableFieldProps}
>
{showSelfDescribe && (
<Input
<Form.Control
name="demographics_gender_description"
id="field-demographics_gender_description"
type="text"
@@ -210,8 +210,8 @@ class DemographicsSection extends React.Component {
className="mt-1"
/>
)}
</EditableField>
<EditableField
</EditableSelectField>
<EditableSelectField
name="demographics_user_ethnicity"
type="select"
hidden
@@ -226,8 +226,8 @@ class DemographicsSection extends React.Component {
values={this.props.formValues.demographics_user_ethnicity}
{...editableFieldProps}
/>
</EditableField>
<EditableField
</EditableSelectField>
<EditableSelectField
name="demographics_income"
type="select"
value={this.props.formValues.demographics_income}
@@ -236,7 +236,7 @@ class DemographicsSection extends React.Component {
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.demographics.income.empty'])}
{...editableFieldProps}
/>
<EditableField
<EditableSelectField
name="demographics_military_history"
type="select"
value={this.props.formValues.demographics_military_history}
@@ -245,7 +245,7 @@ class DemographicsSection extends React.Component {
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.demographics.military_history.empty'])}
{...editableFieldProps}
/>
<EditableField
<EditableSelectField
name="demographics_learner_education_level"
type="select"
value={this.props.formValues.demographics_learner_education_level}
@@ -254,7 +254,7 @@ class DemographicsSection extends React.Component {
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.demographics.learner_education_level.empty'])}
{...editableFieldProps}
/>
<EditableField
<EditableSelectField
name="demographics_parent_education_level"
type="select"
value={this.props.formValues.demographics_parent_education_level}
@@ -263,7 +263,7 @@ class DemographicsSection extends React.Component {
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.demographics.parent_education_level.empty'])}
{...editableFieldProps}
/>
<EditableField
<EditableSelectField
name="demographics_work_status"
type="select"
value={this.props.formValues.demographics_work_status}
@@ -276,7 +276,7 @@ class DemographicsSection extends React.Component {
{...editableFieldProps}
>
{showWorkStatusDescribe && (
<Input
<Form.Control
name="demographics_work_status_description"
id="field-demographics_work_status_description"
type="text"
@@ -287,8 +287,8 @@ class DemographicsSection extends React.Component {
className="mt-1"
/>
)}
</EditableField>
<EditableField
</EditableSelectField>
<EditableSelectField
name="demographics_current_work_sector"
type="select"
value={this.props.formValues.demographics_current_work_sector}
@@ -297,7 +297,7 @@ class DemographicsSection extends React.Component {
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.demographics.current_work_sector.empty'])}
{...editableFieldProps}
/>
<EditableField
<EditableSelectField
name="demographics_future_work_sector"
type="select"
value={this.props.formValues.demographics_future_work_sector}

View File

@@ -25,8 +25,9 @@ exports[`DemographicsSection should render 1`] = `
>
<span
className="pgn__icon"
data-testid="hyperlink-icon"
style={
Object {
{
"height": "1em",
"width": "1em",
}
@@ -43,7 +44,7 @@ exports[`DemographicsSection should render 1`] = `
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19 19H5V5h7V3H3v18h18v-9h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"
d="M19 19H5V5h7V3H3v18h18v-9h-2v7ZM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7Z"
fill="currentColor"
/>
</svg>
@@ -62,14 +63,14 @@ exports[`DemographicsSection should render 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -98,14 +99,14 @@ exports[`DemographicsSection should render 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -126,14 +127,14 @@ exports[`DemographicsSection should render 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -162,14 +163,14 @@ exports[`DemographicsSection should render 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -197,14 +198,14 @@ exports[`DemographicsSection should render 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -233,14 +234,14 @@ exports[`DemographicsSection should render 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -261,14 +262,14 @@ exports[`DemographicsSection should render 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -297,14 +298,14 @@ exports[`DemographicsSection should render 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -325,14 +326,14 @@ exports[`DemographicsSection should render 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -361,14 +362,14 @@ exports[`DemographicsSection should render 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -389,14 +390,14 @@ exports[`DemographicsSection should render 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -425,14 +426,14 @@ exports[`DemographicsSection should render 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -453,14 +454,14 @@ exports[`DemographicsSection should render 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -489,14 +490,14 @@ exports[`DemographicsSection should render 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -517,14 +518,14 @@ exports[`DemographicsSection should render 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -553,14 +554,14 @@ exports[`DemographicsSection should render 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -581,14 +582,14 @@ exports[`DemographicsSection should render 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -617,14 +618,14 @@ exports[`DemographicsSection should render 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -671,8 +672,9 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
>
<span
className="pgn__icon"
data-testid="hyperlink-icon"
style={
Object {
{
"height": "1em",
"width": "1em",
}
@@ -689,7 +691,7 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19 19H5V5h7V3H3v18h18v-9h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"
d="M19 19H5V5h7V3H3v18h18v-9h-2v7ZM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7Z"
fill="currentColor"
/>
</svg>
@@ -720,14 +722,14 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -756,14 +758,14 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -784,14 +786,14 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -820,14 +822,14 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -855,14 +857,14 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -891,14 +893,14 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -919,14 +921,14 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -955,14 +957,14 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -983,14 +985,14 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -1019,14 +1021,14 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -1047,14 +1049,14 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -1083,14 +1085,14 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -1111,14 +1113,14 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -1147,14 +1149,14 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -1175,14 +1177,14 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -1211,14 +1213,14 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -1239,14 +1241,14 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -1275,14 +1277,14 @@ exports[`DemographicsSection should render an Alert if an error occurs 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -1329,8 +1331,9 @@ exports[`DemographicsSection should render an Alert when demographicsOptions pro
>
<span
className="pgn__icon"
data-testid="hyperlink-icon"
style={
Object {
{
"height": "1em",
"width": "1em",
}
@@ -1347,7 +1350,7 @@ exports[`DemographicsSection should render an Alert when demographicsOptions pro
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19 19H5V5h7V3H3v18h18v-9h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"
d="M19 19H5V5h7V3H3v18h18v-9h-2v7ZM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7Z"
fill="currentColor"
/>
</svg>
@@ -1400,8 +1403,9 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
>
<span
className="pgn__icon"
data-testid="hyperlink-icon"
style={
Object {
{
"height": "1em",
"width": "1em",
}
@@ -1418,7 +1422,7 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19 19H5V5h7V3H3v18h18v-9h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"
d="M19 19H5V5h7V3H3v18h18v-9h-2v7ZM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7Z"
fill="currentColor"
/>
</svg>
@@ -1437,14 +1441,14 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -1473,14 +1477,14 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -1501,14 +1505,14 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -1537,14 +1541,14 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -1565,14 +1569,14 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -1601,14 +1605,14 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -1629,14 +1633,14 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -1665,14 +1669,14 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -1693,14 +1697,14 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -1729,14 +1733,14 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -1757,14 +1761,14 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -1793,14 +1797,14 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -1821,14 +1825,14 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -1857,14 +1861,14 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -1885,14 +1889,14 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -1921,14 +1925,14 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -1949,14 +1953,14 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -1985,14 +1989,14 @@ exports[`DemographicsSection should render ethnicity correctly when multiple opt
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -2039,8 +2043,9 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
>
<span
className="pgn__icon"
data-testid="hyperlink-icon"
style={
Object {
{
"height": "1em",
"width": "1em",
}
@@ -2057,7 +2062,7 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19 19H5V5h7V3H3v18h18v-9h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"
d="M19 19H5V5h7V3H3v18h18v-9h-2v7ZM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7Z"
fill="currentColor"
/>
</svg>
@@ -2076,14 +2081,14 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -2112,14 +2117,14 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -2140,14 +2145,14 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -2176,14 +2181,14 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -2204,14 +2209,14 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -2240,14 +2245,14 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -2268,14 +2273,14 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -2304,14 +2309,14 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -2332,14 +2337,14 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -2368,14 +2373,14 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -2396,14 +2401,14 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -2432,14 +2437,14 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -2460,14 +2465,14 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -2496,14 +2501,14 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -2524,14 +2529,14 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -2560,14 +2565,14 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -2588,14 +2593,14 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -2624,14 +2629,14 @@ exports[`DemographicsSection should render ethnicity text correctly 1`] = `
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -2678,8 +2683,9 @@ exports[`DemographicsSection should set user input correctly when user provides
>
<span
className="pgn__icon"
data-testid="hyperlink-icon"
style={
Object {
{
"height": "1em",
"width": "1em",
}
@@ -2696,7 +2702,7 @@ exports[`DemographicsSection should set user input correctly when user provides
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19 19H5V5h7V3H3v18h18v-9h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"
d="M19 19H5V5h7V3H3v18h18v-9h-2v7ZM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7Z"
fill="currentColor"
/>
</svg>
@@ -2715,14 +2721,14 @@ exports[`DemographicsSection should set user input correctly when user provides
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -2751,14 +2757,14 @@ exports[`DemographicsSection should set user input correctly when user provides
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -2779,14 +2785,14 @@ exports[`DemographicsSection should set user input correctly when user provides
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -2815,14 +2821,14 @@ exports[`DemographicsSection should set user input correctly when user provides
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -2850,14 +2856,14 @@ exports[`DemographicsSection should set user input correctly when user provides
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -2886,14 +2892,14 @@ exports[`DemographicsSection should set user input correctly when user provides
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -2914,14 +2920,14 @@ exports[`DemographicsSection should set user input correctly when user provides
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -2950,14 +2956,14 @@ exports[`DemographicsSection should set user input correctly when user provides
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -2978,14 +2984,14 @@ exports[`DemographicsSection should set user input correctly when user provides
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -3014,14 +3020,14 @@ exports[`DemographicsSection should set user input correctly when user provides
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -3042,14 +3048,14 @@ exports[`DemographicsSection should set user input correctly when user provides
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -3078,14 +3084,14 @@ exports[`DemographicsSection should set user input correctly when user provides
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -3106,14 +3112,14 @@ exports[`DemographicsSection should set user input correctly when user provides
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -3142,14 +3148,14 @@ exports[`DemographicsSection should set user input correctly when user provides
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -3170,14 +3176,14 @@ exports[`DemographicsSection should set user input correctly when user provides
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -3206,14 +3212,14 @@ exports[`DemographicsSection should set user input correctly when user provides
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -3234,14 +3240,14 @@ exports[`DemographicsSection should set user input correctly when user provides
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -3270,14 +3276,14 @@ exports[`DemographicsSection should set user input correctly when user provides
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -3324,8 +3330,9 @@ exports[`DemographicsSection should set user input correctly when user provides
>
<span
className="pgn__icon"
data-testid="hyperlink-icon"
style={
Object {
{
"height": "1em",
"width": "1em",
}
@@ -3342,7 +3349,7 @@ exports[`DemographicsSection should set user input correctly when user provides
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19 19H5V5h7V3H3v18h18v-9h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"
d="M19 19H5V5h7V3H3v18h18v-9h-2v7ZM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7Z"
fill="currentColor"
/>
</svg>
@@ -3361,14 +3368,14 @@ exports[`DemographicsSection should set user input correctly when user provides
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -3397,14 +3404,14 @@ exports[`DemographicsSection should set user input correctly when user provides
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -3425,14 +3432,14 @@ exports[`DemographicsSection should set user input correctly when user provides
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -3461,14 +3468,14 @@ exports[`DemographicsSection should set user input correctly when user provides
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -3496,14 +3503,14 @@ exports[`DemographicsSection should set user input correctly when user provides
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -3532,14 +3539,14 @@ exports[`DemographicsSection should set user input correctly when user provides
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -3560,14 +3567,14 @@ exports[`DemographicsSection should set user input correctly when user provides
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -3596,14 +3603,14 @@ exports[`DemographicsSection should set user input correctly when user provides
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -3624,14 +3631,14 @@ exports[`DemographicsSection should set user input correctly when user provides
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -3660,14 +3667,14 @@ exports[`DemographicsSection should set user input correctly when user provides
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -3688,14 +3695,14 @@ exports[`DemographicsSection should set user input correctly when user provides
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -3724,14 +3731,14 @@ exports[`DemographicsSection should set user input correctly when user provides
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -3752,14 +3759,14 @@ exports[`DemographicsSection should set user input correctly when user provides
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -3788,14 +3795,14 @@ exports[`DemographicsSection should set user input correctly when user provides
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -3816,14 +3823,14 @@ exports[`DemographicsSection should set user input correctly when user provides
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -3852,14 +3859,14 @@ exports[`DemographicsSection should set user input correctly when user provides
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit
@@ -3880,14 +3887,14 @@ exports[`DemographicsSection should set user input correctly when user provides
<div
className="pgn-transition-replace-group position-relative"
style={
Object {
{
"height": null,
}
}
>
<div
style={
Object {
{
"padding": ".1px 0",
}
}
@@ -3916,14 +3923,14 @@ exports[`DemographicsSection should set user input correctly when user provides
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={Object {}}
style={{}}
/>
</svg>
Edit

View File

@@ -0,0 +1,19 @@
import React from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
export const withNavigate = Component => {
const WrappedComponent = props => {
const navigate = useNavigate();
return <Component {...props} navigate={navigate} />;
};
return WrappedComponent;
};
export const withLocation = Component => {
const WrappedComponent = props => {
const location = useLocation();
return <Component {...props} location={location.pathname} />;
};
return WrappedComponent;
};

View File

@@ -0,0 +1,38 @@
import React from 'react';
import { fireEvent, render, screen } from '@testing-library/react';
import { withLocation, withNavigate } from './hoc';
const mockedNavigator = jest.fn();
jest.mock('react-router-dom', () => ({
useNavigate: () => mockedNavigator,
useLocation: () => ({
pathname: '/current-location',
}),
}));
// eslint-disable-next-line react/prop-types
const MockComponent = ({ navigate, location }) => (
// eslint-disable-next-line react/button-has-type, react/prop-types
<button data-testid="btn" onClick={() => navigate('/some-route')}>{location}</button>
);
const WrappedComponent = withNavigate(withLocation(MockComponent));
test('Provide Navigation to Component', () => {
render(
<WrappedComponent />,
);
const btn = screen.getByTestId('btn');
fireEvent.click(btn);
expect(mockedNavigator).toHaveBeenCalledWith('/some-route');
});
test('Provide Location Pathname to Component', () => {
render(
<WrappedComponent />,
);
expect(screen.getByTestId('btn').textContent).toContain('/current-location');
});

View File

@@ -1,6 +1,6 @@
import React, { useCallback, useEffect, useState } from 'react';
import { connect, useDispatch } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import PropTypes from 'prop-types';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
@@ -13,7 +13,7 @@ import {
Form,
ModalDialog,
StatefulButton,
} from '@edx/paragon';
} from '@openedx/paragon';
import { closeForm, saveSettingsReset } from '../data/actions';
import { nameChangeSelector } from '../data/selectors';
@@ -21,15 +21,15 @@ import { nameChangeSelector } from '../data/selectors';
import { requestNameChange, requestNameChangeFailure, requestNameChangeReset } from './data/actions';
import messages from './messages';
function NameChangeModal({
const NameChangeModal = ({
targetFormId,
errors,
formValues,
intl,
saveState,
}) {
}) => {
const dispatch = useDispatch();
const { push } = useHistory();
const navigate = useNavigate();
const { username } = getAuthenticatedUser();
const [verifiedNameInput, setVerifiedNameInput] = useState(formValues.verified_name || '');
const [confirmedWarning, setConfirmedWarning] = useState(false);
@@ -69,9 +69,9 @@ function NameChangeModal({
useEffect(() => {
if (saveState === 'complete') {
handleClose();
push(`/id-verification?next=${encodeURIComponent('account/settings')}`);
navigate(`/id-verification?next=${encodeURIComponent('account/settings')}`);
}
}, [handleClose, push, saveState]);
}, [handleClose, navigate, saveState]);
function renderErrors() {
if (Object.keys(errors).length > 0) {
@@ -183,7 +183,7 @@ function NameChangeModal({
</ModalDialog>
);
}
};
NameChangeModal.propTypes = {
targetFormId: PropTypes.string.isRequired,

View File

@@ -2,14 +2,13 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import configureStore from 'redux-mock-store';
import {
fireEvent,
render,
screen,
} from '@testing-library/react';
import { createMemoryHistory } from 'history';
import * as auth from '@edx/frontend-platform/auth';
import { IntlProvider, injectIntl } from '@edx/frontend-platform/i18n';
@@ -28,8 +27,6 @@ jest.mock('react-redux', () => ({
jest.mock('@edx/frontend-platform/auth');
jest.mock('../../data/selectors', () => jest.fn().mockImplementation(() => ({ nameChangeSelector: () => ({}) })));
const history = createMemoryHistory();
const IntlNameChange = injectIntl(NameChange);
const mockStore = configureStore();
@@ -39,7 +36,7 @@ describe('NameChange', () => {
let store = {};
const reduxWrapper = children => (
<Router history={history}>
<Router>
<IntlProvider locale="en">
<Provider store={store}>{children}</Provider>
</IntlProvider>
@@ -168,6 +165,6 @@ describe('NameChange', () => {
props.saveState = 'complete';
render(reduxWrapper(<IntlNameChange {...props} />));
expect(history.location.pathname).toEqual('/id-verification');
expect(window.location.pathname).toEqual('/id-verification');
});
});

View File

@@ -1,18 +1,19 @@
import React from 'react';
import PropTypes from 'prop-types';
import { getConfig } from '@edx/frontend-platform';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { Hyperlink } from '@edx/paragon';
import { Hyperlink } from '@openedx/paragon';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
import Alert from '../Alert';
function ConfirmationAlert(props) {
const ConfirmationAlert = (props) => {
const { email } = props;
const technicalSupportLink = (
<Hyperlink
destination="https://support.edx.org/hc/en-us/articles/206212088-What-if-I-did-not-receive-a-password-reset-message-"
destination={getConfig().PASSWORD_RESET_SUPPORT_LINK}
>
<FormattedMessage
id="account.settings.editable.field.password.reset.button.confirmation.support.link"
@@ -38,7 +39,7 @@ function ConfirmationAlert(props) {
/>
</Alert>
);
}
};
ConfirmationAlert.propTypes = {
email: PropTypes.string.isRequired,

View File

@@ -5,19 +5,17 @@ import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
import Alert from '../Alert';
function RequestInProgressAlert() {
return (
<Alert
className="alert-warning mt-n2"
icon={<FontAwesomeIcon className="mr-2" icon={faExclamationTriangle} />}
>
<FormattedMessage
id="account.settings.editable.field.password.reset.button.forbidden"
defaultMessage="Your previous request is in progress, please try again in few moments."
description="A message displayed when a previous password reset request is still in progress."
/>
</Alert>
);
}
const RequestInProgressAlert = () => (
<Alert
className="alert-warning mt-n2"
icon={<FontAwesomeIcon className="mr-2" icon={faExclamationTriangle} />}
>
<FormattedMessage
id="account.settings.editable.field.password.reset.button.forbidden"
defaultMessage="Your previous request is in progress, please try again in few moments."
description="A message displayed when a previous password reset request is still in progress."
/>
</Alert>
);
export default RequestInProgressAlert;

View File

@@ -2,14 +2,14 @@ import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n';
import { StatefulButton } from '@edx/paragon';
import { StatefulButton } from '@openedx/paragon';
import { resetPassword } from './data/actions';
import messages from './messages';
import ConfirmationAlert from './ConfirmationAlert';
import RequestInProgressAlert from './RequestInProgressAlert';
function ResetPassword(props) {
const ResetPassword = (props) => {
const { email, intl, status } = props;
return (
<div className="form-group">
@@ -47,7 +47,7 @@ function ResetPassword(props) {
{status === 'forbidden' ? <RequestInProgressAlert /> : null}
</div>
);
}
};
ResetPassword.propTypes = {
email: PropTypes.string,

View File

@@ -2,8 +2,9 @@ import { AsyncActionType } from '../data/utils';
export const FETCH_SITE_LANGUAGES = new AsyncActionType('SITE_LANGUAGE', 'FETCH_SITE_LANGUAGES');
export const fetchSiteLanguages = () => ({
export const fetchSiteLanguages = handleNavigation => ({
type: FETCH_SITE_LANGUAGES.BASE,
payload: { handleNavigation },
});
export const fetchSiteLanguagesBegin = () => ({

View File

@@ -19,6 +19,11 @@ const siteLanguageList = [
name: 'Español (Latinoamérica)',
released: true,
},
{
code: 'fa-ir',
name: 'فارسی',
released: true,
},
{
code: 'fr',
name: 'Français',
@@ -69,6 +74,61 @@ const siteLanguageList = [
name: '中文 (简体)',
released: true,
},
{
code: 'pt-pt',
name: 'Português',
released: true,
},
{
code: 'it-it',
name: 'Italian',
released: true,
},
{
code: 'de-de',
name: 'German',
released: true,
},
{
code: 'hi',
name: 'Hindi',
released: true,
},
{
code: 'fr-ca',
name: 'French (CA)',
released: true,
},
{
code: 'te',
name: 'తెలుగు',
released: true,
},
{
code: 'da',
name: 'dansk',
released: true,
},
{
code: 'el',
name: 'Ελληνικά',
released: true,
},
{
code: 'es-es',
name: 'Español (España)',
released: true,
},
{
code: 'sw',
name: 'Kiswahili',
released: true,
},
{
code: 'tr-tr',
name: 'Türkçe (Türkiye)',
released: true,
},
];
export default siteLanguageList;

View File

@@ -10,13 +10,13 @@ import {
import { getSiteLanguageList } from './service';
import { handleFailure } from '../data/utils';
function* handleFetchSiteLanguages() {
function* handleFetchSiteLanguages(action) {
try {
yield put(fetchSiteLanguagesBegin());
const siteLanguageList = yield call(getSiteLanguageList);
yield put(fetchSiteLanguagesSuccess(siteLanguageList));
} catch (e) {
yield call(handleFailure, e, fetchSiteLanguagesFailure);
yield call(handleFailure, e, action.payload.handleNavigation, fetchSiteLanguagesFailure);
}
}

View File

@@ -0,0 +1,101 @@
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import { AppContext } from '@edx/frontend-platform/react';
import {
render, screen, fireEvent,
} from '@testing-library/react';
import configureStore from 'redux-mock-store';
import { IntlProvider, injectIntl } from '@edx/frontend-platform/i18n';
import AccountSettingsPage from '../AccountSettingsPage';
import mockData from './mockData';
const mockDispatch = jest.fn();
jest.mock('@edx/frontend-platform/analytics', () => ({
sendTrackingLogEvent: jest.fn(),
getCountryList: jest.fn(),
}));
jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
useDispatch: () => mockDispatch,
}));
jest.mock('@edx/frontend-platform/auth');
const IntlAccountSettingsPage = injectIntl(AccountSettingsPage);
const middlewares = [thunk];
const mockStore = configureStore(middlewares);
describe('AccountSettingsPage', () => {
let props = {};
let store = {};
const appContext = { locale: 'en', authenticatedUser: { userId: 3, roles: [] } };
const reduxWrapper = children => (
<AppContext.Provider value={appContext}>
<Router>
<IntlProvider locale="en">
<Provider store={store}>
{children}
</Provider>
</IntlProvider>
</Router>
</AppContext.Provider>
);
beforeEach(() => {
store = mockStore(mockData);
props = {
loaded: true,
siteLanguage: {},
formValues: {
username: 'test_username',
accomplishments_shared: false,
name: 'test_name',
email: 'test_email@test.com',
id: 534,
extended_profile: [
{
field_name: 'work_experience',
field_value: '',
},
],
},
fetchSettings: jest.fn(),
};
});
afterEach(() => jest.clearAllMocks());
it('renders AccountSettingsPage correctly with editing enabled', async () => {
const { getByText, rerender, getByLabelText } = render(reduxWrapper(<IntlAccountSettingsPage {...props} />));
const workExperienceText = getByText('Work Experience');
const workExperienceEditButton = workExperienceText.parentElement.querySelector('button');
expect(workExperienceEditButton).toBeInTheDocument();
store = mockStore({
...mockData,
accountSettings: {
...mockData.accountSettings,
openFormId: 'work_experience',
},
});
rerender(reduxWrapper(<IntlAccountSettingsPage {...props} />));
const submitButton = screen.getByText('Save');
expect(submitButton).toBeInTheDocument();
const workExperienceSelect = getByLabelText('Work Experience');
// Use fireEvent.change to simulate changing the selected value
fireEvent.change(workExperienceSelect, { target: { value: '4' } });
fireEvent.click(submitButton);
});
});

View File

@@ -0,0 +1,169 @@
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import { Provider } from 'react-redux';
import renderer from 'react-test-renderer';
import configureStore from 'redux-mock-store';
import { IntlProvider, injectIntl } from '@edx/frontend-platform/i18n';
import EditableSelectField from '../EditableSelectField';
const mockDispatch = jest.fn();
jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
useDispatch: () => mockDispatch,
}));
jest.mock('@edx/frontend-platform/auth');
jest.mock('../data/selectors', () => jest.fn().mockImplementation(() => ({ certPreferenceSelector: () => ({}) })));
const IntlEditableSelectField = injectIntl(EditableSelectField);
const mockStore = configureStore();
describe('EditableSelectField', () => {
let props = {};
let store = {};
const reduxWrapper = children => (
<Router>
<IntlProvider locale="en">
<Provider store={store}>{children}</Provider>
</IntlProvider>
</Router>
);
beforeEach(() => {
store = mockStore();
props = {
name: 'testField',
label: 'Main Label',
emptyLabel: 'Empty Main Label',
type: 'text',
value: 'Test Field',
userSuppliedValue: '',
options: [
{
label: 'Default Option',
value: 'defaultOption',
},
{
label: 'User Options',
group: [
{
label: 'Suboption 1',
value: 'suboption1',
},
],
},
{
label: 'Other Options',
group: [
{
label: 'Suboption 2',
value: 'suboption2',
},
{
label: 'Suboption 3',
value: 'suboption3',
},
],
},
],
saveState: 'default',
error: '',
confirmationMessageDefinition: {
id: 'confirmationMessageId',
defaultMessage: 'Default Confirmation Message',
description: 'Description of the confirmation message',
},
confirmationValue: 'Confirmation Value',
helpText: 'Helpful Text',
isEditing: false,
isEditable: true,
isGrayedOut: false,
};
});
afterEach(() => jest.clearAllMocks());
it('renders EditableSelectField correctly with editing disabled', () => {
const tree = renderer.create(reduxWrapper(<IntlEditableSelectField {...props} />)).toJSON();
expect(tree).toMatchSnapshot();
});
it('renders EditableSelectField correctly with editing enabled', () => {
props = {
...props,
isEditing: true,
};
const tree = renderer.create(reduxWrapper(<IntlEditableSelectField {...props} />)).toJSON();
expect(tree).toMatchSnapshot();
});
it('renders EditableSelectField with an error', () => {
const errorProps = {
...props,
error: 'This is an error message',
};
const tree = renderer.create(reduxWrapper(<IntlEditableSelectField {...errorProps} />)).toJSON();
expect(tree).toMatchSnapshot();
});
it('renders selectOptions when option has a group', () => {
const propsWithGroup = {
...props,
options: [
{
label: 'User Options',
group: [
{
label: 'Suboption 1',
value: 'suboption1',
},
],
},
],
};
const tree = renderer.create(reduxWrapper(<IntlEditableSelectField {...propsWithGroup} />)).toJSON();
expect(tree).toMatchSnapshot();
});
it('renders selectOptions when option does not have a group', () => {
const propsWithoutGroup = {
...props,
options: [
{
label: 'Default Option',
value: 'defaultOption',
},
],
};
const tree = renderer.create(reduxWrapper(<IntlEditableSelectField {...propsWithoutGroup} />)).toJSON();
expect(tree).toMatchSnapshot();
});
it('renders selectOptions with multiple groups', () => {
const propsWithGroups = {
...props,
options: [
{
label: 'Mixed Options',
group: [
{
label: 'Suboption 1',
value: 'suboption1',
},
{
label: 'Suboption 2',
value: 'suboption2',
},
],
},
],
};
const tree = renderer.create(reduxWrapper(<IntlEditableSelectField {...propsWithGroups} />)).toJSON();
expect(tree).toMatchSnapshot();
});
});

View File

@@ -1,45 +1,65 @@
import React from 'react';
import renderer from 'react-test-renderer';
import { IntlProvider, injectIntl } from '@edx/frontend-platform/i18n';
import { AppProvider } from '@edx/frontend-platform/react';
import { initializeMockApp, mergeConfig, setConfig } from '@edx/frontend-platform';
import { BrowserRouter as Router } from 'react-router-dom';
import { mergeConfig, setConfig } from '@edx/frontend-platform';
import JumpNav from '../JumpNav';
import configureStore from '../../data/configureStore';
const IntlJumpNav = injectIntl(JumpNav);
describe('JumpNav', () => {
mergeConfig({
ENABLE_DEMOGRAPHICS_COLLECTION: false,
ENABLE_ACCOUNT_DELETION: true,
});
let props = {};
let store;
beforeEach(() => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: true,
roles: [],
},
});
props = {
intl: {},
displayDemographicsLink: false,
};
store = configureStore({
notificationPreferences: {
showPreferences: false,
},
});
});
it('should not render Optional Information link', () => {
it('should not render Optional Information or delete account link', () => {
setConfig({
ENABLE_ACCOUNT_DELETION: false,
});
const tree = renderer.create((
// Had to wrap the following in a router or I will receive an error stating:
// "Invariant failed: You should not use <NavLink> outside a <Router>"
<Router>
<IntlProvider locale="en">
<IntlProvider locale="en">
<AppProvider store={store}>
<IntlJumpNav {...props} />
</IntlProvider>
</Router>
</AppProvider>
</IntlProvider>
))
.toJSON();
expect(tree).toMatchSnapshot();
});
it('should render Optional Information link', () => {
it('should render Optional Information and delete account link', () => {
setConfig({
ENABLE_DEMOGRAPHICS_COLLECTION: true,
ENABLE_ACCOUNT_DELETION: true,
});
props = {
@@ -48,12 +68,11 @@ describe('JumpNav', () => {
};
const tree = renderer.create((
// Same as previous test
<Router>
<IntlProvider locale="en">
<IntlProvider locale="en">
<AppProvider store={store}>
<IntlJumpNav {...props} />
</IntlProvider>
</Router>
</AppProvider>
</IntlProvider>
))
.toJSON();

View File

@@ -0,0 +1,485 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`EditableSelectField renders EditableSelectField correctly with editing disabled 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
{
"height": null,
}
}
>
<div
style={
{
"padding": ".1px 0",
}
}
>
<div
className="form-group"
>
<div
className="d-flex align-items-start"
>
<h6
aria-level="3"
>
Main Label
</h6>
<button
className="ml-3 btn btn-link"
disabled={false}
onClick={[Function]}
type="button"
>
<svg
aria-hidden="true"
className="svg-inline--fa fa-pencil-alt fa-w-16 mr-1"
data-icon="pencil-alt"
data-prefix="fas"
focusable="false"
role="img"
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={{}}
/>
</svg>
Edit
</button>
</div>
<p
className={null}
data-hj-suppress={true}
>
Test Field
</p>
<p
className="small text-muted mt-n2"
>
Default Confirmation Message
</p>
</div>
</div>
</div>
`;
exports[`EditableSelectField renders EditableSelectField correctly with editing enabled 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
{
"height": null,
}
}
>
<div
style={
{
"padding": ".1px 0",
}
}
>
<form
onSubmit={[Function]}
>
<div
className="pgn__form-group"
>
<label
className="pgn__form-label h6 d-block"
htmlFor="field-testField"
size="sm"
>
Main Label
</label>
<div
className="pgn__form-control-decorator-group"
>
<text
aria-describedby="field-testField-2"
className="has-value form-control is-invalid"
data-hj-suppress={true}
id="field-testField"
name="testField"
onBlur={[Function]}
onChange={[Function]}
type="text"
value="Test Field"
>
<option
value="defaultOption"
>
Default Option
</option>
<optgroup
label="User Options"
>
<option
value="suboption1"
>
Suboption 1
</option>
</optgroup>
<optgroup
label="Other Options"
>
<option
value="suboption2"
>
Suboption 2
</option>
<option
value="suboption3"
>
Suboption 3
</option>
</optgroup>
</text>
</div>
<div
className="pgn__form-text pgn__form-text-default"
>
<div>
Helpful Text
</div>
</div>
<div
className="pgn__form-control-description pgn__form-text pgn__form-text-invalid"
id="field-testField-2"
>
<span
className="pgn__icon"
>
<svg
aria-hidden={true}
fill="none"
focusable={false}
height={24}
role="img"
viewBox="0 0 24 24"
width={24}
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"
fill="currentColor"
/>
</svg>
</span>
<div>
</div>
</div>
</div>
<p>
<button
aria-disabled={false}
aria-live="assertive"
className="pgn__stateful-btn pgn__stateful-btn-state-default mr-2 btn btn-primary"
disabled={false}
onClick={[Function]}
type="submit"
>
<span
className="d-flex align-items-center justify-content-center"
>
<span>
Save
</span>
</span>
</button>
<button
className="btn btn-outline-primary"
disabled={false}
onClick={[Function]}
type="button"
>
Cancel
</button>
</p>
</form>
</div>
</div>
`;
exports[`EditableSelectField renders EditableSelectField with an error 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
{
"height": null,
}
}
>
<div
style={
{
"padding": ".1px 0",
}
}
>
<div
className="form-group"
>
<div
className="d-flex align-items-start"
>
<h6
aria-level="3"
>
Main Label
</h6>
<button
className="ml-3 btn btn-link"
disabled={false}
onClick={[Function]}
type="button"
>
<svg
aria-hidden="true"
className="svg-inline--fa fa-pencil-alt fa-w-16 mr-1"
data-icon="pencil-alt"
data-prefix="fas"
focusable="false"
role="img"
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={{}}
/>
</svg>
Edit
</button>
</div>
<p
className={null}
data-hj-suppress={true}
>
Test Field
</p>
<p
className="small text-muted mt-n2"
>
Default Confirmation Message
</p>
</div>
</div>
</div>
`;
exports[`EditableSelectField renders selectOptions when option does not have a group 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
{
"height": null,
}
}
>
<div
style={
{
"padding": ".1px 0",
}
}
>
<div
className="form-group"
>
<div
className="d-flex align-items-start"
>
<h6
aria-level="3"
>
Main Label
</h6>
<button
className="ml-3 btn btn-link"
disabled={false}
onClick={[Function]}
type="button"
>
<svg
aria-hidden="true"
className="svg-inline--fa fa-pencil-alt fa-w-16 mr-1"
data-icon="pencil-alt"
data-prefix="fas"
focusable="false"
role="img"
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={{}}
/>
</svg>
Edit
</button>
</div>
<p
className={null}
data-hj-suppress={true}
>
Test Field
</p>
<p
className="small text-muted mt-n2"
>
Default Confirmation Message
</p>
</div>
</div>
</div>
`;
exports[`EditableSelectField renders selectOptions when option has a group 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
{
"height": null,
}
}
>
<div
style={
{
"padding": ".1px 0",
}
}
>
<div
className="form-group"
>
<div
className="d-flex align-items-start"
>
<h6
aria-level="3"
>
Main Label
</h6>
<button
className="ml-3 btn btn-link"
disabled={false}
onClick={[Function]}
type="button"
>
<svg
aria-hidden="true"
className="svg-inline--fa fa-pencil-alt fa-w-16 mr-1"
data-icon="pencil-alt"
data-prefix="fas"
focusable="false"
role="img"
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={{}}
/>
</svg>
Edit
</button>
</div>
<p
className={null}
data-hj-suppress={true}
>
Test Field
</p>
<p
className="small text-muted mt-n2"
>
Default Confirmation Message
</p>
</div>
</div>
</div>
`;
exports[`EditableSelectField renders selectOptions with multiple groups 1`] = `
<div
className="pgn-transition-replace-group position-relative"
style={
{
"height": null,
}
}
>
<div
style={
{
"padding": ".1px 0",
}
}
>
<div
className="form-group"
>
<div
className="d-flex align-items-start"
>
<h6
aria-level="3"
>
Main Label
</h6>
<button
className="ml-3 btn btn-link"
disabled={false}
onClick={[Function]}
type="button"
>
<svg
aria-hidden="true"
className="svg-inline--fa fa-pencil-alt fa-w-16 mr-1"
data-icon="pencil-alt"
data-prefix="fas"
focusable="false"
role="img"
style={{}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"
fill="currentColor"
style={{}}
/>
</svg>
Edit
</button>
</div>
<p
className={null}
data-hj-suppress={true}
>
Test Field
</p>
<p
className="small text-muted mt-n2"
>
Default Confirmation Message
</p>
</div>
</div>
</div>
`;

View File

@@ -1,194 +1,197 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`JumpNav should not render Optional Information link 1`] = `
exports[`JumpNav should not render Optional Information or delete account link 1`] = `
<div
className="jump-nav jump-nav-sm position-sticky pt-3"
data-testid="redux-provider"
>
<ul
className="list-unstyled"
style={Object {}}
<div
data-testid="browser-router"
>
<li
className=""
<div
className="jump-nav px-2.25 jump-nav-sm position-sticky pt-3"
>
<a
aria-current="page"
className="active"
href="/#basic-information"
onClick={[Function]}
style={Object {}}
<ul
className="list-unstyled"
style={{}}
>
Account Information
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#profile-information"
onClick={[Function]}
style={Object {}}
>
Profile Information
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#social-media"
onClick={[Function]}
style={Object {}}
>
Social Media Links
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#site-preferences"
onClick={[Function]}
style={Object {}}
>
Site Preferences
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#linked-accounts"
onClick={[Function]}
style={Object {}}
>
Linked Accounts
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#delete-account"
onClick={[Function]}
style={Object {}}
>
Delete My Account
</a>
</li>
</ul>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#basic-information"
isActive={[Function]}
onClick={[Function]}
>
Account Information
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#profile-information"
isActive={[Function]}
onClick={[Function]}
>
Profile Information
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#social-media"
isActive={[Function]}
onClick={[Function]}
>
Social Media Links
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#site-preferences"
isActive={[Function]}
onClick={[Function]}
>
Site Preferences
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#linked-accounts"
isActive={[Function]}
onClick={[Function]}
>
Linked Accounts
</a>
</li>
</ul>
</div>
</div>
</div>
`;
exports[`JumpNav should render Optional Information link 1`] = `
exports[`JumpNav should render Optional Information and delete account link 1`] = `
<div
className="jump-nav jump-nav-sm position-sticky pt-3"
data-testid="redux-provider"
>
<ul
className="list-unstyled"
style={Object {}}
<div
data-testid="browser-router"
>
<li
className=""
<div
className="jump-nav px-2.25 jump-nav-sm position-sticky pt-3"
>
<a
aria-current="page"
className="active"
href="/#basic-information"
onClick={[Function]}
style={Object {}}
<ul
className="list-unstyled"
style={{}}
>
Account Information
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#profile-information"
onClick={[Function]}
style={Object {}}
>
Profile Information
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#demographics-information"
onClick={[Function]}
style={Object {}}
>
Optional Information
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#social-media"
onClick={[Function]}
style={Object {}}
>
Social Media Links
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#site-preferences"
onClick={[Function]}
style={Object {}}
>
Site Preferences
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#linked-accounts"
onClick={[Function]}
style={Object {}}
>
Linked Accounts
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#delete-account"
onClick={[Function]}
style={Object {}}
>
Delete My Account
</a>
</li>
</ul>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#basic-information"
isActive={[Function]}
onClick={[Function]}
>
Account Information
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#profile-information"
isActive={[Function]}
onClick={[Function]}
>
Profile Information
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#demographics-information"
isActive={[Function]}
onClick={[Function]}
>
Optional Information
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#social-media"
isActive={[Function]}
onClick={[Function]}
>
Social Media Links
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#site-preferences"
isActive={[Function]}
onClick={[Function]}
>
Site Preferences
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#linked-accounts"
isActive={[Function]}
onClick={[Function]}
>
Linked Accounts
</a>
</li>
<li
className=""
>
<a
aria-current="page"
className="active"
href="/#delete-account"
isActive={[Function]}
onClick={[Function]}
>
Delete My Account
</a>
</li>
</ul>
</div>
</div>
</div>
`;

View File

@@ -0,0 +1,112 @@
const mockData = {
accountSettings: {
loading: false,
loaded: true,
loadingError: null,
data: null,
values: {
username: 'test_username',
country: 'AD',
accomplishments_shared: false,
name: 'test_name',
email: 'test_email@test.com',
id: 533,
verified_name: null,
extended_profile: [
{
field_name: 'work_experience',
field_value: '',
},
],
gender: null,
'pref-lang': 'en',
shouldDisplayDemographicsSection: false,
demographicsOptions: false,
},
errors: {},
confirmationValues: {},
drafts: {},
saveState: null,
timeZones: [
{
time_zone: 'Africa/Abidjan',
description: 'Africa/Abidjan (GMT, UTC+0000)',
},
],
countryTimeZones: [
{
time_zone: 'Europe/Andorra',
description: 'Europe/Andorra (CET, UTC+0100)',
},
],
previousSiteLanguage: null,
deleteAccount: {
status: null,
errorType: null,
},
siteLanguage: {
loading: false,
loaded: true,
loadingError: null,
siteLanguageList: [
{
code: 'en',
name: 'English',
released: true,
},
],
},
resetPassword: {
status: null,
},
nameChange: {
saveState: null,
errors: {},
},
thirdPartyAuth: {
providers: [
{
id: 'oa2-google-oauth2',
name: 'Google',
connected: false,
accepts_logins: true,
connectUrl: 'http://localhost:18000/auth/login/google-oauth2/?auth_entry=account_settings&next=%2Faccount%2Fsettings',
disconnectUrl: 'http://localhost:18000/auth/disconnect/google-oauth2/?',
},
],
disconnectionStatuses: {},
errors: {},
},
verifiedName: null,
mostRecentVerifiedName: {},
verifiedNameHistory: {
use_verified_name_for_certs: false,
results: [],
},
profileDataManager: null,
},
notificationPreferences: {
showPreferences: false,
courses: {
status: 'success',
courses: [],
pagination: {
count: 0,
currentPage: 1,
hasMore: false,
totalPages: 1,
},
},
preferences: {
status: 'idle',
updatePreferenceStatus: 'idle',
selectedCourse: null,
preferences: [],
apps: [],
nonEditable: {},
},
},
};
export default mockData;

View File

@@ -2,7 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { Hyperlink, StatefulButton } from '@edx/paragon';
import { Hyperlink, StatefulButton } from '@openedx/paragon';
import Alert from '../Alert';
import { disconnectAuth } from './data/actions';

View File

@@ -4,8 +4,10 @@ import {
reducer as accountSettingsReducer,
storeName as accountSettingsStoreName,
} from '../account-settings';
import notificationPreferencesReducer from '../notification-preferences/data/reducers';
const createRootReducer = () => combineReducers({
[accountSettingsStoreName]: accountSettingsReducer,
notificationPreferences: notificationPreferencesReducer,
});
export default createRootReducer;

View File

@@ -5,16 +5,14 @@ import { getConfig } from '@edx/frontend-platform';
import messages from './messages';
function Head({ intl }) {
return (
<Helmet>
<title>
{intl.formatMessage(messages['account.page.title'], { siteName: getConfig().SITE_NAME })}
</title>
<link rel="shortcut icon" href={getConfig().FAVICON_URL} type="image/x-icon" />
</Helmet>
);
}
const Head = ({ intl }) => (
<Helmet>
<title>
{intl.formatMessage(messages['account.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,

View File

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

View File

@@ -1,4 +1,7 @@
import { useEffect, useState } from 'react';
import { getConfig } from '@edx/frontend-platform';
import { logError } from '@edx/frontend-platform/logging';
import { breakpoints, useWindowSize } from '@openedx/paragon';
import {
IDLE_STATUS, LOADING_STATUS, SUCCESS_STATUS, FAILURE_STATUS,
@@ -53,3 +56,19 @@ export function useRedirect() {
return redirect;
}
export function useFeedbackWrapper() {
useEffect(() => {
try {
// eslint-disable-next-line no-undef
window.usabilla_live = lightningjs?.require('usabilla_live', getConfig().LEARNER_FEEDBACK_URL);
} catch (error) {
logError('Error loading usabilla_live', error);
}
}, []);
}
export function useIsOnMobile() {
const windowSize = useWindowSize();
return windowSize.width <= breakpoints.small.minWidth;
}

View File

@@ -1,32 +1 @@
import arMessages from './messages/ar.json';
import caMessages from './messages/ca.json';
// no need to import en messages-- they are in the defaultMessage field
import es419Messages from './messages/es_419.json';
import frMessages from './messages/fr.json';
import zhcnMessages from './messages/zh_CN.json';
import heMessages from './messages/he.json';
import idMessages from './messages/id.json';
import kokrMessages from './messages/ko_kr.json';
import plMessages from './messages/pl.json';
import ptbrMessages from './messages/pt_br.json';
import ruMessages from './messages/ru.json';
import thMessages from './messages/th.json';
import ukMessages from './messages/uk.json';
const messages = {
ar: arMessages,
'es-419': es419Messages,
fr: frMessages,
'zh-cn': zhcnMessages,
ca: caMessages,
he: heMessages,
id: idMessages,
'ko-kr': kokrMessages,
pl: plMessages,
'pt-br': ptbrMessages,
ru: ruMessages,
th: thMessages,
uk: ukMessages,
};
export default messages;
export default [];

View File

@@ -1,359 +0,0 @@
{
"account.settings.message.duplicate.tpa.provider": "حساب {provider} الذي حددته موصول من قبل بحساب آخر على {siteName}.",
"account.settings.message.managed.settings": "إعدادات ملفك الشخصي يديرها {ManagerTitle}. اتصل بمديرك أو ب{support} للحصول على المساعدة.",
"account.settings.message.managed.settings.support": "الدعم",
"account.settings.page.heading": "إعدادات الحساب",
"account.settings.loading.message": "التحميل جارٍ...",
"account.settings.loading.error": "خطأ: {error}",
"account.settings.banner.beta.language": "لقد قمت بضبط لغتك على {beta_language}، وهي حاليا غير مترجمة بالكامل. يمكنك مساعدتنا في إتمام ترجمة هذه اللغة من خلال الانضمام إلى مجتمع Transifex وإضافة ترجمات من الإنجليزية للمتعلمين الذين يتحدثون {beta_language}.",
"account.settings.banner.beta.language.action.switch.back": "العودة إلى {previous_language}",
"account.settings.banner.beta.language.action.help.translate": "ساعد في الترجمة إلى {beta_language}",
"account.settings.section.account.information": "معلومات الحساب",
"account.settings.section.account.information.description": "تتضمن هذه الإعدادات معلومات أساسية عن حسابك.",
"account.settings.section.profile.information": "معلومات الملف الشخصي",
"account.settings.section.demographics.information": "معلومات اختيارية",
"account.settings.section.site.preferences": "تفضيلات الموقع",
"account.settings.section.linked.accounts": "الحسابات الموصولة",
"account.settings.section.linked.accounts.description": "يمكنك وصل حسابات هويتك لتبسيط تسجيل دخولك إلى {siteName}.",
"account.settings.field.username": "اسم المستخدم",
"account.settings.field.username.help.text": "الاسم الذي يعرّفك على {siteName}. لا يمكنك تغيير اسم المستخدم الخاص بك.",
"account.settings.field.full.name": "الاسم الكامل",
"account.settings.field.full.name.empty": "إضافة الاسم",
"account.settings.field.full.name.help.text": "الاسم المستعمل للتحقق من هويتك والذي يظهر في شهاداتك.",
"account.settings.field.full.name.help.text.default": "الاسم الذي يظهر في ملفك الشخصي العامّ.",
"account.settings.field.full.name.help.text.default.certificate": "سيظهر هذا الاسم في شهاداتك و سجلّاتك العامّة.",
"account.settings.field.name.verified": "اسم متحقَّق منه",
"account.settings.field.name.verified.help.text.verified": "تم التحقق من هذا الاسم عن طريق بطاقة تعريف ذات صورة.",
"account.settings.field.name.verified.help.text.verified.proctored": "تم التحقق من هذا الاسم عن طريق المراقبة.",
"account.settings.field.name.verified.help.text.verified.certificate": "تم التحقق من هذا الاسم عن طريق بطاقة هوية ذات صورة، وتم اختياره للظهور في الشهادات والسجلات العامة.",
"account.settings.field.name.verified.help.text.verified.proctored.certificate": "تم التحقق من هذا الاسم من خلال المراقبة، وتم تحديده للظهور في الشهادات والسجلات العامة.",
"account.settings.field.name.verified.help.text.submitted": "تم تسليم طلب التحقق. في العادة يستغرق هذا 48 ساعة أو أقل. لا يمكن تغيير الاسم المتحقَّق منه في هذا الوقت.",
"account.settings.field.name.verified.help.text.submitted.proctored": "تم تسليم امتحانك المراقَب. لا يمكن تغيير الاسم المتحقَّق منه في هذا الوقت. رجاءً أعد التفقد بعد 2-5 أيام.",
"account.settings.field.name.verified.help.text.submitted.certificate": "عند نجاح التحقق من الهوية، سيظهر هذا الاسم على شهاداتك و سجلاتك العامة. لا يمكن تغيير الاسم المتحقَّق منه في هذا الوقت.",
"account.settings.field.name.verified.help.text.submitted.proctored.certificate": "بمجرد اجتياز امتحانك المراقب للمراجعة، سيظهر هذا الاسم في شهادتك و سجلاتك العامة. لا يمكن تغيير الاسم المتحقَّق منه في هذا الوقت.",
"account.settings.field.name.verified.verification.help": "أدخل اسمك كما يظهر في بطاقة تعريف الطالب أو الموظف الخاصة بك، أو بطاقة تعريفك الصادرة عن الحكومة.",
"account.settings.field.full.name.help.text.submitted": "تم تسليم طلب التحقق. يستغرق هذا عادةً 48 ساعة أو أقل. لا يمكن تغيير الاسم الكامل في هذا الوقت.",
"account.settings.field.full.name.help.text.submitted.proctored": "تم تسليم امتحانك المراقب. لا يمكن تغيير الاسم الكامل في هذا الوقت. يرجى التحقق مرة أخرى خلال 2-5 أيام.",
"account.settings.field.full.name.help.text.submitted.certificate": "عند نجاح التحقق من الهوية، سيظهر هذا الاسم على الشهادات والسجلات العامة. لا يمكن تغيير الاسم الكامل في هذا الوقت.",
"account.settings.field.full.name.help.text.submitted.proctored.certificate": "بمجرد اجتياز امتحانك المراقب للمراجعة، سيظهر هذا الاسم في شهاداتك وسجلاتك العامة. لا يمكن تغيير الاسم الكامل في هذا الوقت.",
"account.settings.field.name.verified.success.message": "اكتمل طلب التحقق من هويتك بنجاح. لديك الآن خيار تحديد الاسم الذي تفضل ظهوره على شهاداتك وسجلاتك العامة.",
"account.settings.field.name.verified.success.message.header": "اكتمل طلب تغيير اسمك!",
"account.settings.field.name.verified.failure.message": "لم تنجح آخر محاولاتك للتحقق من هويتك. تم إرجاع إعدادات الحساب ذات الصلة إلى وضعها السابق.",
"account.settings.field.name.verified.failure.message.header": "لم نستطع التحقق من هويتك.",
"account.settings.field.name.verified.failure.message.help.link": "اعرف المزيد عن التحقق من الهوية.",
"account.settings.field.name.verified.submitted.message": "تم تسليم طلب التحقق من هويتك و عادة ما يستغرق إكماله ما بين 24 و 48 ساعة.",
"account.settings.field.name.verified.submitted.message.certificate": "عند الموافقة على طلبك، سيظهر اسمك المحدَّث على جميع الشهادات السجلات العامة ذات الصلة.",
"account.settings.field.name.verified.submitted.message.header": "طلب تغيير اسمك يكاد يكتمل!",
"account.settings.field.email": "البريد الالكتروني (تسجيل الدخول)",
"account.settings.field.email.empty": "إضافة عنوان البريد الإلكتروني",
"account.settings.field.email.confirmation": "لقد أرسلنا رسالة تأكيد إلى {value}. انقر على الرابط في الرسالة لتحديث عنوان بريدك الإلكتروني.",
"account.settings.field.email.help.text": "على هذا العنوان تصلك الرسائل من {siteName} و من فرق المساقات.",
"account.settings.field.secondary.email": "عنوان بريد الاستعادة الإلكتروني.",
"account.settings.field.secondary.email.empty": "إضافة عنوان بريد إلكتروني لاستعادة حسابك",
"account.settings.field.secondary.email.confirmation": "لقد أرسلنا رسالة تأكيد إلى {value}. انقر على الرابط في الرسالة لتحديث عنوان بريد الاستعادة الإلكتروني الخاص بك.",
"account.settings.email.field.confirmation.header": "تعليق عملية التأكيد",
"account.settings.field.dob": "سنة الميلاد",
"account.settings.field.dob.empty": "إضافة سنة الميلاد",
"account.settings.field.year_of_birth.options.empty": "تحديد سنة الميلاد",
"account.settings.field.dob.month": "الشهر",
"account.settings.field.dob.year": "السنة",
"account.settings.field.dob.form.button": "يرجى تأكيد تاريخ ميلادك",
"account.settings.field.dob.form.title": "تأكيد تاريخ ميلادك",
"account.settings.field.dob.form.help.text": "نطلب معلومة تاريخ الميلاد لمساعدتنا على الالتزام بواجباتنا القانونية.",
"account.settings.field.dob.form.success": "شكرا لك على إدخال تاريخ ميلادك.",
"account.settings.field.month_of_birth.options.empty": "تحديد شهر الميلاد",
"account.settingsfield.dob.error.general": "حدث خطأ تقني. رجاءً حاول مجددا.",
"account.settings.field.country": "البلد",
"account.settings.field.country.empty": "إضافة البلد ",
"account.settings.field.country.options.empty": "اختر البلد",
"account.settings.field.state": "المنطقة / الولاية / المحافظة",
"account.settings.field.state.empty": "إضافة المنطقة / الولاية / المحافظة",
"account.settings.field.state.options.empty": "حدد المنطقة",
"account.settings.field.site.language": "لغة الموقع",
"account.settings.field.site.language.help.text": "اللغة المستخدمة في كافة أقسام هذا الموقع. يتوفّر هذا الموقع حاليًا بعدد محدود من اللغات.",
"account.settings.field.education": "المستوى التعليمي",
"account.settings.field.education.empty": "إضافة المستوى التعليمي",
"account.settings.field.education.levels.empty": "اختر مستوى تعليميًّا",
"account.settings.field.education.levels.p": "دكتوراه",
"account.settings.field.education.levels.m": "ماجستير / ماستر أو شهادة مهنيّة",
"account.settings.field.education.levels.b": "بكالوريوس / ليسانس",
"account.settings.field.education.levels.a": "درجة الزمالة / دبلوم الدراسات الجامعية",
"account.settings.field.education.levels.hs": "الثانوية العامة / البكالوريا",
"account.settings.field.education.levels.jhs": "المدرسة الإعدادية / المتوسطة",
"account.settings.field.education.levels.el": "المدرسة الابتدائية / الأساسية",
"account.settings.field.education.levels.none": "دون تعليم رسمي",
"account.settings.field.education.levels.o": "نوع آخر من التعليم",
"account.settings.field.gender": "الجنس",
"account.settings.field.gender.empty": "إضافة الجنس",
"account.settings.field.gender.options.empty": "اختر جنسًا",
"account.settings.field.gender.options.f": "أنثى",
"account.settings.field.gender.options.m": "ذكر",
"account.settings.field.gender.options.o": "آخر",
"account.settings.field.language.proficiencies": "لغة التحدّث",
"account.settings.field.language.proficiencies.empty": "إضافة لغة التحدث",
"account.settings.field.language_proficiencies.options.empty": "اختر لغة",
"account.settings.field.time.zone": "المنطقة الزمنية",
"account.settings.field.time.zone.empty": "ضبط المنطقة الزمنية",
"account.settings.field.time.zone.description": "حدد المنطقة الزمنية لعرض تواريخ المساقات. إذا لم تحدد منطقة زمنية، فسيتم عرض تواريخ المساق، بما في ذلك المواعيد النهائية للواجبات بالتوقيت المحلّي للمتصفح.",
"account.settings.field.time.zone.default": "الافتراضي (المنطقة الزمنية المحلية)",
"account.settings.field.time.zone.all": "جميع المناطق الزمنية",
"account.settings.field.time.zone.country": "المناطق الزمنية للبلدان",
"account.settings.section.social.media": "روابط التواصل الإجتماعي",
"account.settings.section.social.media.description": "اختياريًا، اربط حساباتك الشخصية بأيقونات التواصل الاجتماعي في ملفك على {siteName}.",
"account.settings.field.social.platform.name.linkedin": "لينكد إن",
"account.settings.field.social.platform.name.linkedin.empty": "إضافة سيرة لينكد إن",
"account.settings.jump.nav.delete.account": "حذف حسابي",
"account.settings.field.social.platform.name.twitter": "تويتر",
"account.settings.field.social.platform.name.twitter.empty": "إضافة صفحة تويتر",
"account.settings.field.social.platform.name.facebook": "فيسبوك",
"account.settings.field.social.platform.name.facebook.empty": "إضافة حساب فيسبوك",
"account.settings.editable.field.action.save": "حفظ",
"account.settings.editable.field.action.cancel": "إلغاء",
"account.settings.editable.field.action.edit": "تعديل",
"account.settings.static.field.empty": "لا قيمة محددة. رجاءً اتصل بمديرك في {enterprise} ليقوم بالتعديلات.",
"account.settings.static.field.empty.no.admin": "لا قيمة محددة.",
"account.settings.field.name.certificate.select": "في حال التأشير، سيظهر هذا الاسم في شهاداتك و سجلاتك العامة.",
"account.settings.field.name.modal.certificate.title": "اختر اسمًا مفضلًا للشهادات والسجلات العامة",
"account.settings.field.name.modal.certificate.select": "اختر اسمًا",
"account.settings.field.name.modal.certificate.option.full": "الاسم الكامل",
"account.settings.field.name.modal.certificate.option.verified": "اسم متحقَّق منه",
"account.settings.field.name.modal.certificate.button.choose": "اختيار الاسم",
"account.settings.coaching.consent.welcome.header": "لنبدأ.",
"account.settings.coaching.consent.welcome.subheader": "نحن هنا لأجلك من البداية حتى النهاية",
"account.settings.coaching.consent.description": "تتضمن برامج MicroBachelors مرافقة تركز على مهنتك و تعليمك و كيفية تحقيقك للنتائج، و ذلك من خلال التواصل الفردي مع خبير متمرس. إن كنت مهتمًا، فيرجى تزويدنا بالمعلومات أدناه و النقر على \"إرسال\"، و سيتصل بك شريكنا في المرافقة عبر البريد الإلكتروني و/أو الرسائل النصية لمساعدتك على المضي قدمًا. تنطبق الشروط والأحكام.*",
"account.settings.coaching.consent.text-messaging.disclaimer": "* خدمات المرافقة مشمولة دون تكاليف إضافية للمتعلمين الذين لديهم أرقام هواتف أمريكية. تتضمن المرافقة رسائل نصية دورية. قد تنطبق أسعار على الرسائل والبيانات. أرسل STOP للانسحاب.",
"account.settings.coaching.consent.accept-coaching": "سجّل للاستفادة من خدمات المرافقة",
"account.settings.coaching.consent.decline-coaching": "أفضّل ألا يٌتصَل بي بخصوص خدمات المرافقة المجانية",
"account.settings.coaching.consent.label.name": "رجاءً أكّد اسمك",
"account.settings.coaching.consent.label.phone-number": "أدخل رقم هاتفك الجوّال",
"account.settings.coaching.consent.success.header": "نجحت العملية!",
"account.settings.coaching.consent.success.message": "أنت الآن مشترك في المرافقة. ترقّب رسالة عبر البريد الإلكتروني أو خدمة الرسائل القصيرة في في الأيام المقبلة.",
"account.settings.coaching.consent.success.continue": "البدء في مساقي",
"account.settings.coaching.managed.support": "الدعم",
"account.settings.coaching.managed.alert": "اسمك يديره {ManagerTitle}. اتصل بمديرك للحصول على المساعدة.",
"account.settings.field.phone_number": "رقم الهاتف",
"account.settings.field.phone_number.empty": "إضافة رقم هاتف",
"account.settings.field.coaching_consent": "الموافقة على المرافقة",
"account.settings.field.coaching_consent.tooltip": "تتضمن برامج MicroBachelors مرافقة قائمة على الرسائل النصية، تساعدك على إقران تجاربك التعلّمية مع أهدافك المهنية من خلال النصائح الفردية. خدمات المرافقة مشمولة دون تكاليف إضافية، وهي متوفرة للمتعلمين الذين لديهم أرقام هواتف جوالة أمريكية. تنطبق أسعار المراسلة القياسية. أرسل 'STOP' في أي وقت للانسحاب من الرسائل.",
"account.settings.field.coaching_consent.error": "مطلوب رقم هاتف أمريكي صحيح للتسجيل في المرافقة",
"account.settings.delete.account.before.proceeding": "قبل المتابعة، يرجى {actionLink}.",
"account.settings.delete.account.header": "حذف حسابي",
"account.settings.delete.account.subheader": "نأسف لذهابك!",
"account.settings.delete.account.text.1": "ترجى الملاحظة: إن حذف حسابك وبياناتك الشخصية له أثر دائم و لا يمكن التراجع عنه. لن يكون بمقدور {siteName} استعادة حسابك ولا البيانات التي يتم حذفها.",
"account.settings.delete.account.text.2": "بمجرد حذف حسابك، فإنك لن تستطيع استخدامه لمتابعة المساقات على {siteName}.",
"account.settings.delete.account.text.2.edX": "بمجرد حذف حسابك، فإنك لن تستطيع استخدامه لمتابعة المساقات على تطبيق edX ولا edx.org ولا أي موقع آخر تستضيفه edX. وهذا يشمل الوصول إلى edx.org من نظام صاحب العمل أو الجامعة و الوصول إلى المواقع الخاصة التي تقدمها MIT Open Learning و Wharton Executive Education و Harvard Medical School.",
"account.settings.delete.account.text.3.link": "اتّبع هذه التعليمات لطباعة أو تحميل شهادة",
"account.settings.delete.account.text.warning": "تحذير: حذف الحساب أثره دائم. يرجى قراءة ما ورد أعلاه بعناية قبل المتابعة. هذا إجراء غير رجعي، و لن تتمكن بعده من استخدام نفس البريد الإلكتروني على {siteName}.",
"account.settings.delete.account.text.change.instead": "هل تريد بدلاً من ذلك تغيير بريدك الإلكتروني أو اسمك أو كلمة المرور الخاصة بك؟",
"account.settings.delete.account.button": "حذف حسابي",
"account.settings.delete.account.please.activate": "تفعيل حسابك",
"account.settings.delete.account.please.confirm": "تأكيد حسابك",
"account.settings.delete.account.please.unlink": "فصل جميع حسابات التواصل الاجتماعي",
"account.settings.delete.account.modal.header": "هل أنت متأكد؟",
"account.settings.delete.account.modal.text.1": "لقد اخترت \"حذف حسابي\". إن حذف حسابك وبياناتك الشخصية ذو أثر دائم لا يمكن التراجع عنه. لن يكون بمقدور {siteName} استعادة حسابك و لا البيانات التي حذفت.",
"account.settings.delete.account.modal.text.2": "إن واصلت، فلن تستطيع استخدام هذا الحساب لمتابعة المساقات على {siteName}.",
"account.settings.delete.account.modal.text.2.edX": "إن واصلت، فلن تستطيع استخدام هذا الحساب لمتابعة المساقات على على تطبيق edX و لا edx.org و لا أي موقع آخر تستضيفه edX. وهذا يشمل الوصول إلى edx.org من نظام صاحب العمل أو الجامعة و الوصول إلى المواقع الخاصة التي يقدمها MIT Open Learning و Wharton Executive Education و Harvard Medical School.",
"account.settings.delete.account.modal.enter.password": "إن كنت لا تزال ترغب في المتابعة و حذف حسابك، فيرجى إدخال كلمة المرور:",
"account.settings.delete.account.modal.confirm.delete": "تعم، احذف",
"account.settings.delete.account.modal.confirm.cancel": "لا",
"account.settings.delete.account.error.unable.to.delete": "لم نستطع حذف الحساب",
"account.settings.delete.account.error.no.password": "كلمة المرور مطلوبة",
"account.settings.delete.account.error.invalid.password": "كلمة المرور غير صحيحة",
"account.settings.delete.account.error.unable.to.delete.details": "عذراً، حدث خطأ أثناء محاولة معالجة طلبك. رجاءً أعد المحاولة لاحقًا.",
"account.settings.delete.account.modal.after.header": "نأسف لذهابك! سيُحذف حسابك في ظرف وجيز.",
"account.settings.delete.account.modal.after.text": "حذف الحساب، بما في ذلك من إزالة من القوائم البريدية، إجراء قد يستغرق بضعة أسابيع حتى يكتمل عبر نظامنا. إن كنت تريد قبل ذلك الحين إيقاف تلقي البريد الإلكتروني، فيرجى إلغاء الاشتراك من تذييل أي بريد إلكتروني.",
"account.settings.delete.account.modal.after.button": "إغلاق ",
"account.settings.delete.account.text.3.edX": "قد تفقد كذلك إمكانية الوصول إلى الشهادات الموثقة و كذا مؤهلات البرامج الأخرى مثل شهادات MicroMasters. يمكنك الاحتفاظ بنسخة عنها لديك قبل المواصلة إلى الحذف. {actionLink}.",
"account.settings.delete.account.text.3": "قد تفقد كذلك إمكانية الوصول إلى الشهادات الموثقة و كذا مؤهلات البرامج الأخرى. يمكنك الاحتفاظ بنسخة عنها لديك قبل المواصلة إلى الحذف.",
"account.settings.message.demographics.service.issue": "حدث خطأ أثناء محاولة استخراج أو حفظ معلومات حسابك. رجاءً أعد المحاولة لاحقًا.",
"account.settings.field.demographics.gender": "هوية الجنس",
"account.settings.field.demographics.gender.empty": "إضافة هوية الجنس",
"account.settings.field.demographics.gender.options.empty": "حدد هوية الجنس",
"account.settings.field.demographics.gender_description": "وصف هوية الجنس",
"account.settings.field.demographics.gender_description.empty": "أدخل الوصف",
"account.settings.field.demographics.ethnicity": "هوية العرق/ الأصل",
"account.settings.field.demographics.ethnicity.empty": "إضافة هوية العرق / الأصل",
"account.settings.field.demographics.ethnicity.options.empty": "اختر كل ما ينطبق",
"account.settings.field.demographics.income": "دخل الأسرة",
"account.settings.field.demographics.income.empty": "إضافة دخل الأسرة",
"account.settings.field.demographics.income.options.empty": "حدد نطاقًا لدخل الأسرة",
"account.settings.field.demographics.military_history": "الوضعية إزاء الخدمة العسكرية في الولايات المتحدة",
"account.settings.field.demographics.military_history.empty": "إضافة الوضعية إزاء الخدمة العسكرية",
"account.settings.field.demographics.military_history.options.empty": "اختر الوضعية إزاء الخدمة العسكرية",
"account.settings.field.demographics.learner_education_level": "مستواك التعليمي",
"account.settings.field.demographics.learner_education_level.empty": "إضافة المستوى التعليمي",
"account.settings.field.demographics.parent_education_level": "مستوى الوالدين/الأولياء التعليمي",
"account.settings.field.demographics.parent_education_level.empty": "إضافة المستوى التعليمي",
"account.settings.field.demographics.education_level.options.empty": "حدد المستوى التعليمي",
"account.settings.field.demographics.work_status": "الحالة الوظيفية",
"account.settings.field.demographics.work_status.empty": "إضافة الحالة الوظيفية",
"account.settings.field.demographics.work_status.options.empty": "حدد الحالة الوظيفية",
"account.settings.field.demographics.work_status_description": "وصف الحالة الوظيفية",
"account.settings.field.demographics.work_status_description.empty": "أدخل الوصف",
"account.settings.field.demographics.current_work_sector": "مجال العمل الحالي",
"account.settings.field.demographics.current_work_sector.empty": "إضافة مجال العمل",
"account.settings.field.demographics.future_work_sector": "مجال العمل المستقبلي",
"account.settings.field.demographics.future_work_sector.empty": "إضافة مجال العمل",
"account.settings.field.demographics.work_sector.options.empty": "حدد مجال العمل",
"account.settings.section.demographics.why": "ما هي غاية {siteName} من جمع هذه المعلومات؟",
"account.settings.name.change.title.id": "تغيير الاسم هذا يتطلب التحقق من الهوية",
"account.settings.name.change.title.begin": "قبل أن نبدأ",
"account.settings.name.change.warning.one": "تحذير: يقوم هذا الإجراء بتحديث الاسم الذي يظهر على جميع الشهادات التي تم الحصول عليها على هذا الحساب في الماضي و أي شهادات تحصل عليها حاليا أو مستقبلاً.",
"account.settings.name.change.warning.two": "لا يمكن التراجع عن هذا الإجراء دون التحقق من هويتك.",
"account.settings.name.change.id.name.label": "أدخل اسمك كما يظهر في بطاقة تعريف الطالب أو العمل أو بطاقة الهوية الصادرة عن الحكومة.",
"account.settings.name.change.id.name.placeholder": "أدخل الاسم الموجود في بطاقة تعريفك ذات الصورة.",
"account.settings.name.change.error.valid.name": "رجاءً أدخل اسما صحيحا.",
"account.settings.name.change.error.general": "حدث خطأ تقني. رجاءً حاول مجددًا.",
"account.settings.name.change.continue": "مواصلة",
"account.settings.name.change.cancel": "إلغاء",
"error.notfound.message": "الصفحة التي تبحث عنها غير متوفرة أو هناك خطأ في العنوان. رجاءً تحقق من العنوان و حاول مجددًا.",
"account.settings.editable.field.password.reset.button.confirmation.support.link": "الدعم الفني",
"account.settings.editable.field.password.reset.button.confirmation": "لقد أرسلنا رسالة إلى {email}. انقر على الرابط في الرسالة لإعادة ضبط كلمة المرور الخاصة بك. لم تصلك الرسالة؟ اتصل بـ{technicalSupportLink}.",
"account.settings.editable.field.password.reset.button": "إعادة ضبط كلمة المرور",
"account.settings.editable.field.password.reset.button.forbidden": "طلبك السابق في تقدّم، رجاءً حاول مجددًا بعد لحظات قليلة.",
"account.settings.editable.field.password.reset.label": "كلمة المرور",
"account.settings.sso.link.account": "تسجيل الدخول باستخدام {name}",
"account.settings.sso.account.connected": "موصول",
"account.settings.sso.account.disconnect.error": "حدثت مشكلة أثناء فصل هذا الحساب، اتصل بالدعم إن استمرت المشكلة.",
"account.settings.sso.unlink.account": "فصل حساب {name}",
"account.settings.sso.no.providers": "لا يمكن وصل أي حسابات في الوقت الراهن.",
"account.page.title": "الحساب | {siteName}",
"id.verification.access.blocked.denied": "لا يمكننا التحقق من هويتك في الوقت الراهن. إن لم تكن قد فعّلت حسابك بعد، فيرجى تفقد مجلد الرسائل غير المرغوب فيها بحثًا عن بريد التفعيل الإلكتروني من {email}.",
"id.verification.next": "التالي",
"id.verification.support": "الدعم",
"id.verification.example.card.alt": "مثال بطاقة تعريف صحيحة بالاسم الكامل والصورة.",
"id.verification.requirements.title": "متطلبات التحقق باستخدام الصورة",
"id.verification.requirements.description": "لإكمال التحقق بالصورة، ستحتاج ما يلي:",
"id.verification.requirements.card.device.title": "جهاز مزود بكاميرا",
"id.verification.requirements.card.device.allow": "السماح",
"id.verification.requirements.card.id.title": "بطاقة تعريف بها صورة",
"id.verification.requirements.card.id.text": "تحتاج إلى بطاقة تعريف صالحة تحتوي اسمك الكامل وصورتك، كرخصة القيادة أو جواز السفر مثلاً.",
"id.verification.privacy.title": "معلومات الخصوصية",
"id.verification.privacy.need.photo.question": "ما حاجة {siteName} لصورتي؟",
"id.verification.privacy.need.photo.answer": "نستخدم صور التحقق الخاصة بك لتأكيد هويتك ولضمان صحة شهادتك.",
"id.verification.privacy.do.with.photo.question": "ماذا يُفعَل بهذه الصورة في {siteName}؟",
"id.verification.privacy.do.with.photo.answer": "نقوم بتشفير صورتك بشكل آمن وإرسالها إلى خدمة الترخيص الخاصة بنا للمراجعة. صورتك و معلوماتك لا تُحفَظ و لا تظهر في أي مكان على {siteName} بعد اكتمال عملية التحقق.",
"id.verification.access.blocked.title": "التحقق من الهوية",
"id.verification.access.blocked.enrollment": "أنت حاليا غير ملتحق بأي مساق يتطلب التحقق من الهوية.",
"id.verification.access.blocked.pending": "لقد سلّمت من قبل معلومات التحقق الخاصة بك. ستصلك رسالة على لوحة المعلومات الخاصة بك عند اكتمال عملية التحقق (عادةً في ظرف 5 أيام).",
"id.verification.photo.take": "التقاط صورة ",
"id.verification.photo.retake": "إعادة التقاط الصورة؟",
"id.verification.photo.enable.detection": "تفعيل اكتشاف الوجوه",
"id.verification.photo.enable.detection.portrait.help.text": "في حال التأشير، سيبرز مربع حول وجهك. يمكن رؤية وجهك بوضوح إن كان المربع المحيط به أزرق اللون. أما إن كان وجهك في وضع غير جيد أو غير قابل للاكتشاف، فسيكون المربع أحمر اللون.",
"id.verification.photo.enable.detection.id.help.text": "في حال التأشير، سيظهر مربع حول صورة وجهك في بطاقة الهوية. يمكن رؤية وجهك بوضوح إن كان المربع المحيط به أزرق اللون. أما إن كان وجهك في وضع غير جيد أو غير قابل للاكتشاف، فسيكون المربع أحمر اللون.",
"id.verification.photo.feedback.correct": "موضع الوجه جيد.",
"id.verification.photo.feedback.two.faces": "تم اكتشاف أكثر من وجه واحد.",
"id.verification.photo.feedback.no.faces": "لم يتم اكتشاف أي وجه.",
"id.verification.photo.feedback.top.left": "الموضع خاطئ. أعلى اليسار.",
"id.verification.photo.feedback.top.center": "الموضع خاطئ. أعلى الوسط.",
"id.verification.photo.feedback.top.right": "الموضع خاطئ. أعلى اليمين.",
"id.verification.photo.feedback.center.left": "الموضع خاطئ. وسط اليسار.",
"id.verification.photo.feedback.center.center": "الموضع خاطئ. قريب جدًا من الكاميرا.",
"id.verification.photo.feedback.center.right": "الموضع خاطئ. وسط اليمين.",
"id.verification.photo.feedback.bottom.left": "الموضع خاطئ. أسفل اليسار.",
"id.verification.photo.feedback.bottom.center": "الموضع خاطئ. أسفل الوسط.",
"id.verification.photo.feedback.bottom.right": "الموضع خاطئ. أسفل اليمين.",
"id.verification.camera.access.title": "صلاحيات الكاميرا",
"id.verification.camera.access.title.success": "الوصول للكاميرا ممكن",
"id.verification.camera.access.title.failed": "تعذّر الوصول للكاميرا.",
"id.verification.camera.access.click.allow": "رجاءً تأكد من النقر على \"السماح\"",
"id.verification.camera.access.enable": "تفعيل الكاميرا",
"id.verification.camera.access.problems": "لديك مشاكل؟",
"id.verification.camera.access.skip": "تَخَطَّ و قم برفع ملفات صور بدلاً من ذلك.",
"id.verification.camera.access.success": "يبدو أن كاميرا جهازك جاهزة و تعمل.",
"id.verification.camera.access.failure": "يبدو أننا غير قادرين على الوصول إلى كاميرا جهازك. ستحتاج لرفع ملف صورتك و صورة بطاقة هويتك.",
"id.verification.camera.access.failure.temporary": "يبدو أننا غير قادرين على الوصول إلى الكاميرا. رجاءً تحقق من أن كاميرا جهازك متصلة ومن أنك قد سمحت للمتصفح بالوصول إليها.",
"id.verification.camera.access.failure.temporary.chrome": "لتفعيل الوصول للكاميرا في متصفح كروم:",
"id.verification.camera.access.failure.temporary.chrome.step1": "افتح كروم.",
"id.verification.camera.access.failure.temporary.chrome.step2": "توجه إلى المزيد > الإعدادات.",
"id.verification.camera.access.failure.temporary.chrome.step2.windows": "لنظام ويندوز: Alt+F أو Alt+E أو F10 متبوعاً بـ SPACEBAR",
"id.verification.camera.access.failure.temporary.chrome.step2.mac": "لنظام ماك: Command+,",
"id.verification.camera.access.failure.temporary.chrome.step3": "تحت علامة التبويب \"الخصوصية والأمان\"، اختر \"إعدادات الموقع\" ثم \"الكاميرا\".",
"id.verification.camera.access.failure.temporary.chrome.step4": "ضمن \"قائمة الحظر\"، ابحث عن \"edx.org\" وحدده.",
"id.verification.camera.access.failure.temporary.chrome.step5": "في قسم \"الصلاحيات\"، قم بتحديث صلاحيات الكاميرا إلى \"السماح\".",
"id.verification.camera.access.failure.temporary.ie11": "لتفعيل الوصول للكاميرا في متصفح انترنت إكسبلورر:",
"id.verification.camera.access.failure.temporary.ie11.step1": "افتح إدارة إعدادات Flash Player عن طريق الانتقال إلى إعدادات Windows > لوحة التحكم > Flash Player.",
"id.verification.camera.access.failure.temporary.ie11.step2": "حدد علامة التبويب \"Camera and Mic\" (الكاميرا والميكروفون)، ثم حدد الزر \"Camera and Microphone Settings by Site\" (إعدادات الكاميرا والميكروفون حسب الموقع).",
"id.verification.camera.access.failure.temporary.ie11.step3": "اختر \"edx.org\" من قائمة مواقع ويب وقم بتغيير الصلاحيات من خلال تحديد \"السماح\" في القائمة المنسدلة.",
"id.verification.camera.access.failure.temporary.firefox": "لتمكين الوصول للكاميرا في متصفّح فايرفوكس: ",
"id.verification.camera.access.failure.temporary.firefox.step1": "فتح متصفّح فايرفوكس.",
"id.verification.camera.access.failure.temporary.firefox.step2": "أدخل \"about:preferences\" في شريط عنوان الرابط.",
"id.verification.camera.access.failure.temporary.firefox.step3": "حدد علامة التبويب \"الخصوصية والأمان\"، وانتقل إلى القسم \"الصلاحيات\".",
"id.verification.camera.access.failure.temporary.firefox.step4": "بجوار \"Camera\" (الكاميرا)، حدد \"Settings…\" (الإعدادات…) الزر.",
"id.verification.camera.access.failure.temporary.firefox.step5": "في شريط البحث أدخل \"edx.org.\"",
"id.verification.camera.access.failure.temporary.firefox.step6": "في عمود الحالة لـ \"edx.org,\" حدد \"السماح\" من القائمة المنسدلة.",
"id.verification.camera.access.failure.temporary.firefox.step7": "اختر \"حفظ التغييرات.\"",
"id.verification.camera.access.failure.temporary.safari": "تمكين الوصول للكاميرا في متصفّح سفاري: ",
"id.verification.camera.access.failure.temporary.safari.step1": "فتح متصفّح سفاري.",
"id.verification.camera.access.failure.temporary.safari.step2": "انقر فوق قائمة تطبيق سفاري، ثم حدد \"Preferences\" (التفضيلات). يمكنك أيضاً استخدام الأمرCommand+, كاختصار للوحة المفاتيح",
"id.verification.camera.access.failure.temporary.safari.step3": "حدد علامة التبويب \"مواقع الويب\" ثم حدد \"كاميرا\".",
"id.verification.camera.access.failure.temporary.safari.step4": "حدد \"edx.org\" وقم بتغيير صلاحيات الكاميرا إلى \"السماح\".",
"id.verification.camera.access.failure.unsupported": "يبدو أن متصفحك لا يدعم الوصول إلى الكاميرا.",
"id.verification.camera.access.failure.unsupported.chrome.explanation": "لا يدعم متصفح Chrome حاليًا الوصول إلى الكاميرا على أجهزة iOS مثل أجهزة iPhone و iPad.",
"id.verification.camera.access.failure.unsupported.instructions": "رجاءً استخدم متصفحًا آخر لإكمال التحقق من الهوية.",
"id.verification.photo.tips.title": "نصائح مفيدة بخصوص الصورة",
"id.verification.photo.tips.description": "بعد ذلك، سنحتاج منك التقاط صورة لوجهك. يرجى مراجعة النصائح المفيدة أدناه.",
"id.verification.photo.tips.list.title": "نصائح بخصوص الصورة",
"id.verification.photo.tips.list.description": "لالتقاط صورة ناجحة، يُرجى التأكّد ممّا يلي:",
"id.verification.photo.tips.list.well.lit": "أنّ وجهك مُضاء جيدًا.",
"id.verification.photo.tips.list.inside.frame": "أنّ وجهك كلَّه داخل إطار الصورة.",
"id.verification.portrait.photo.title.camera": "التقط صورة لنفسك",
"id.verification.portrait.photo.instructions.camera": "عندما يكون وجهك في موضعه، استخدم زر 'التقاط صورة' أدناه لالتقاط صورتك.",
"id.verification.camera.help.sight.question": "ماذا إن لم أتمكن من رؤية صورة الكاميرا أو إن لم أتمكن من رؤية صورتي لتحديد أي جانب مرئي؟",
"id.verification.camera.help.sight.answer.portrait": "قد تتمكن من إكمال إجراء التقاط الصور دون مساعدة، لكن قد يتطلب الأمر بضع محاولات لضبط موضع الكاميرا بشكل صحيح.يختلف موضع الكاميرا المثالي من حاسوب ﻵخر، لكن عمومًا يكون أفضل موضع لتصوير الرأس تقريبًا على بعد 12-18 بوصة (30-45 سنتمترًا) من الكاميرا، مع وضع رأسك في المنتصف بالنسبة إلى شاشة الحاسوب. إن تم رفض الصور التي ترسلها، فحاول تغيير اتجاه الكمبيوتر أو الكاميرا لتغيير زاوية الإضاءة.",
"id.verification.camera.help.sight.answer.id": "قد تتمكن من إكمال إجراء التقاط الصور دون مساعدة، لكن قد يتطلب الأمر بضع محاولات لضبط موضع الكاميرا بشكل صحيح.يختلف موضع الكاميرا المثالي من حاسوب ﻵخر، لكن عمومًا يكون أفضل موضع لتصوير بطاقة تعريف تقريبًا على بعد 8-12 بوصة (20-30 سنتمترًا) من الكاميرا، مع وضع البطاقة في المنتصف بالنسبة للكاميرا. إن تم رفض الصور التي ترسلها، فحاول تغيير اتجاه الكمبيوتر أو الكاميرا لتغيير زاوية الإضاءة. إن أكثر سبب للرفض هو عدم القدرة على قراءة نص بطاقة التعريف.",
"id.verification.camera.help.difficulty.question.portrait": "ماذا لو واجهت صعوبة في تثبيت رأسي في الموضع المناسب للكاميرا؟",
"id.verification.camera.help.difficulty.question.id": "ماذا لو واجهت صعوبة في تثبيت بطاقة هويتي في الموضع المناسب للكاميرا؟",
"id.verification.camera.help.difficulty.answer": "إن احتجت لمساعدة في التقاط صورة لإرسالها، فاتصل بدعم {siteName} للحصول على اقتراحات إضافية.",
"id.verification.id.photo.unclear.question": "هل صورة بطاقة تعريفك غير واضحة أو ضبابية جدًا؟",
"id.verification.id.tips.title": "نصائح مفيدة بخصوص بطاقة التعريف",
"id.verification.id.tips.description": "بعد ذلك، عليك التقاط صورة لبطاقة تعريف صالحة تتضمن اسمك الكامل مع صورة، مثل رخصة القيادة أو جواز السفر.يرجى منك تجهيز بطاقة تعريفك.",
"id.verification.id.tips.list.well.lit": "أن تكون بطاقة تعريفك مضاءة جيدًا.",
"id.verification.id.tips.list.clear": "تأكد من قدرتك على رؤية صورتك وقراءة اسمك بوضوح.",
"id.verification.id.photo.title.camera": "التقط صورة لبطاقة تعريفك",
"id.verification.id.photo.title.upload": "ارفع صورة لبطاقة تعريفك",
"id.verification.id.photo.preview.alt": "معاينة صورة الهوية.",
"id.verification.id.photo.instructions.camera": "عندما تكون بطاقتك في موضعها، استخدم زر 'التقاط صورة' أدناه لالتقاط صورتك. يرجى استخدام جواز سفر أو رخصة قيادة أو بطاقة تعريف أخرى تتضمن اسمك الكامل وصورة لوجهك.",
"id.verification.id.photo.instructions.upload": "يرجى رفع صورة لبطاقة تعريفك. تأكد من أن البطاقة كاملة داخل الإطار و أنها مضاءة جيدًا. يجب أن يكون حجم الملف أقل من 10 ميجابايت. الأنساق المدعومة:",
"id.verification.id.photo.instructions.upload.error.invalidFileType": "الملف الذي حددته ليس ضمن أنواع الصورة المدعومة. اختر رجاءً من بين الأنساق التالية:",
"id.verification.id.photo.instructions.upload.error.fileTooLarge": "الملف الذي حددته كبير جداً. رجاءً أعد المحاولة باستخدام ملف ذي حجم أقل من 10 ميجابايت.",
"id.verification.name.check.title": "تحقق مرة أخرى من اسمك",
"id.verification.name.check.instructions": "هل الاسم أدناه يطابق الاسم الموجود في بطاقة تعريفك ذات الصورة. إن لم يكن كذلك، فقم بتحديث الاسم أدناه ليطابق بطاقة تعريفك.",
"id.verification.name.check.mismatch.information": "إن كان الاسم أدناه لا يطابق بطاقة تعريفك، فسيتم رفض تأكيد هويتك.",
"id.verification.name.error": "رجاءً أدخل اسمك كما يظهر في بطاقة تعريفك ذات الصورة.",
"id.verification.account.name.warning.prefix": "تُرجى الملاحظة:",
"id.verification.account.name.settings": "إعدادات الحساب",
"id.verification.name.label": "الاسم",
"id.verification.account.name.photo.alt": "صورة بطاقة هويتك التي ستُسلَّم.",
"id.verification.review.title": "مراجعة صورك",
"id.verification.review.description": "يُرجى التأكّد من أنّ الصور والمعلومات التي قدّمتها تمكّننا من التحقّق من هويّتك. ",
"id.verification.review.portrait.label": "صورتك الشخصية",
"id.verification.review.portrait.alt": "صورة وجهك التي ستُسلَّم.",
"id.verification.review.portrait.retake": "إعادة التقاط الصورة الشخصية",
"id.verification.review.id.label": "بطاقة تعريفك",
"id.verification.review.id.alt": "صورة بطاقة تعريفك التي ستُسلَّم.",
"id.verification.review.id.retake": "إعادة التقاط صورة بطاقة الهوية",
"id.verification.review.confirm": "تسليم",
"id.verification.submission.alert.error.face": "مطلوبة صورة لوجهك. رجاءً أعد التقاط صورتك الشخصية.",
"id.verification.submission.alert.error.id": "مطلوبة صورة لبطاقة تعريفك. رجاءً أعد التقاط صورة لبطاقة تعريفك.",
"id.verification.submission.alert.error.name": "مطلوب اسم حساب صحيح. يرجى تحديث اسم حسابك لمطابقة الاسم على بطاقة تعريفك.",
"id.verification.submission.alert.error.unsupported": "واحد أو أكثر من الملفات التي قمت برفعها في نَسقٍ غير مدعوم. رجاءً اختر مما يلي:",
"id.verification.review.error": "{siteName} صفحة دعم",
"id.verification.submitted.title": "التحقق من الهوية جارٍ",
"id.verification.submitted.text": "لقد تلقينا معلوماتك و نحن الآن نتحقق من هويتك. سيتم إخطارك عند اكتمال عملية التحقق (عادةً في ظرف 5 أيام). إلى ذلكم الحين، لا يزال يمكنك الوصول لجميع محتويات المساق المتاحة.",
"id.verification.return.dashboard": "العودة للوحة المعلومات",
"id.verification.return.course": "العودة للمساق",
"id.verification.return.generic": "العودة",
"id.verification.photo.upload.help.title": "قم يدلا من هذا برفع صورة",
"id.verification.photo.camera.help.title": "استخدم الكاميرا بدلاً من هذا",
"id.verification.photo.upload.help.text": "إن واجهتك مشكلة في استخدام مُلتقط الصور أعلاه، فقد ترغب بدﻷ من ذلك في رفع صورة. لرفع صورة، انقر على الزر أدناه.",
"id.verification.photo.camera.help.text": "إن واجهتك مشكلة في رفع صورة أعلاه، فقد ترغب بدلا من ذلك في استخدام كاميرا جهازك. لاستخدام الكاميرا، انقر على الزر أدناه.",
"id.verification.upload.help.button": "انتقل إلى وضع الرفع",
"id.verification.camera.help.button": "انتقل إلى وضع الكاميرا",
"id.verification.request.camera.access.instructions": "حتى تلتقط صورة باستخدام الكاميرا، قد تتلقى طلبًا من المتصفح للوصول إلى الكاميرا. {clickAllow}",
"id.verification.requirements.account.managed.alert": "إعدادات حسابك يديرها {managerTitle}. إن لم يكن الاسم في بطاقة هويتك ذات الصورة. مطابقًا للاسم الذي في حسابك، فيرجى الاتصال بالمسؤول {profileDataManager} أو ب{support} للحصول على المساعدة قبل إتمام عملية التحقق من الصورة..",
"id.verification.requirements.card.device.text": "أنت بحاجة إلى جهاز مزود بكاميرا. إذا تلقيت طلبًا من المتصفح للوصول إلى كاميرا جهازك، فتأكد رجاءً من النقر على {السماح}.",
"id.verification.account.name.summary.alert": "إعدادات حسابك يديرها {managerTitle}. إن لم يكن الاسم في بطاقة هويتك ذات الصورة. مطابقًا للاسم الذي في حسابك، فيرجى الاتصال بالمسؤول {profileDataManager} أو ب{support} للحصول على المساعدة قبل إتمام عملية التحقق من الصورة..",
"idv.submission.alert.error": "\nواجهنا خطأ فني أثناء محاولة رفع طلب التحقق من الهوية\nقد تكون هذه مشكلة مؤقتة، لذا يرجى المحاولة مجددًا بعد بضع دقائق\nإن استمرت المشكلة، فيرجى الذهاب إلى {support_link} للحصول على المساعدة.",
"id.verification.account.name.edit": "تعديل {sr}"
}

View File

@@ -1,11 +0,0 @@
{
"siteheader.links.courses": "Courses",
"siteheader.links.programs": "Programs & Degrees",
"siteheader.links.schools": "Schools & Partners",
"siteheader.user.menu.dashboard": "Dashboard",
"siteheader.user.menu.profile": "Profile",
"siteheader.user.menu.account.settings": "Account",
"siteheader.user.menu.logout": "Logout",
"siteheader.user.menu.login": "Login",
"siteheader.user.menu.register": "Sign Up"
}

View File

@@ -1,359 +0,0 @@
{
"account.settings.message.duplicate.tpa.provider": "La cuenta de {provider} seleccionada ya está vinculada con otra cuenta de {siteName}. ",
"account.settings.message.managed.settings": "Los ajustes en el perfil son administrados por {managerTitle}. Contacte su administrador o {support} para obtener ayuda.",
"account.settings.message.managed.settings.support": "soporte",
"account.settings.page.heading": "Configuración de cuenta",
"account.settings.loading.message": "Cargando...",
"account.settings.loading.error": "Error: {error}",
"account.settings.banner.beta.language": "Ha establecido su idioma en {beta_language}, el cual no está traducido completamente. Puede ayudarnos a traducir este idioma totalmente uniéndose la comunidad Transifex y adicionando traducciones desde el Inglés para los estudiantes que hablan {beta_language}.",
"account.settings.banner.beta.language.action.switch.back": "Regresar a {previous_language}",
"account.settings.banner.beta.language.action.help.translate": "Ayude a traducir a {beta_language}",
"account.settings.section.account.information": "Información de la cuenta",
"account.settings.section.account.information.description": "Estas configuraciones incluyen información básica sobre tu cuenta.",
"account.settings.section.profile.information": "Información del perfil",
"account.settings.section.demographics.information": "Información opcional",
"account.settings.section.site.preferences": "Preferencias del sitio",
"account.settings.section.linked.accounts": "Cuentas vinculadas",
"account.settings.section.linked.accounts.description": "Puedes vincular tus cuentas de redes sociales para simplificar el proceso de iniciar sesión en {siteName}.",
"account.settings.field.username": "Nombre de usuario",
"account.settings.field.username.help.text": "El nombre que lo identifica en {siteName}. No podrá cambiar el nombre de usuario.",
"account.settings.field.full.name": "Nombre completo",
"account.settings.field.full.name.empty": "Añade nombre",
"account.settings.field.full.name.help.text": "El nombre que es usado para la verificación de identidad y aparece en sus certificados.",
"account.settings.field.full.name.help.text.default": "El nombre que aparece en tu perfil público.",
"account.settings.field.full.name.help.text.default.certificate": "Este nombre está seleccionado para aparecer en tus certificados y registros públicos.",
"account.settings.field.name.verified": "Nombre verificado",
"account.settings.field.name.verified.help.text.verified": "Este nombre ha sido verificado por una identificación con foto.",
"account.settings.field.name.verified.help.text.verified.proctored": "Este nombre ha sido verificado por supervisión.",
"account.settings.field.name.verified.help.text.verified.certificate": "Este nombre ha sido verificado por una identificación con foto y está seleccionado para aparecer en sus certificados y registros públicos.",
"account.settings.field.name.verified.help.text.verified.proctored.certificate": "Este nombre se ha verificado mediante supervisión y se ha seleccionado para que aparezca en sus certificados y registros públicos.",
"account.settings.field.name.verified.help.text.submitted": "La verificación ha sido enviada. Este proceso usualmente toma 48 horas o menos. El nombre verificado no puede ser modificado en este momento. ",
"account.settings.field.name.verified.help.text.submitted.proctored": "Su examen supervisado ha sido enviado. El nombre verificado no se puede cambiar en este momento. Vuelva a consultar en 2-5 días.",
"account.settings.field.name.verified.help.text.submitted.certificate": "Cuando el proceso de verificación de identidad sea exitoso, este nombre aparecerá en tus certificados y registros públicos. El nombre verificado no puede ser cambiado en este momento. ",
"account.settings.field.name.verified.help.text.submitted.proctored.certificate": "Una vez que su examen supervisado pase la revisión, este nombre aparecerá en su certificado y en los registros públicos. El nombre verificado no se puede cambiar en este momento.",
"account.settings.field.name.verified.verification.help": "Ingrese su nombre tal como aparece en su tarjeta de identificación vigente de estudiante, trabajo o emitida por el gobierno.",
"account.settings.field.full.name.help.text.submitted": "La verificación ha sido enviada. Este proceso usualmente toma 48 horas o menos. El nombre verificado no puede ser modificado en este momento. ",
"account.settings.field.full.name.help.text.submitted.proctored": "Su examen supervisado ha sido enviado. El nombre completo no se puede cambiar en este momento. Vuelva a consultar en 2-5 días.",
"account.settings.field.full.name.help.text.submitted.certificate": "En cuanto el proceso de verificación de identidad sea exitoso, este nombre aparecerá en tus certificados y registros públicos. El nombre completo no puede ser cambiado en este momento. ",
"account.settings.field.full.name.help.text.submitted.proctored.certificate": "Una vez que su examen supervisado pase la revisión, este nombre aparecerá en sus certificados y registros públicos. El nombre completo no se puede cambiar en este momento.",
"account.settings.field.name.verified.success.message": "Tu solicitud de verificación de identidad se ha completado exitosamente. Ahora puedes seleccionar el nombre prefieres que aparezca en tus certificados y registros públicos.",
"account.settings.field.name.verified.success.message.header": "¡Tu solicitud de cambio de nombre está completada!",
"account.settings.field.name.verified.failure.message": "Tu más reciente intento de verificación de ID no fue aprobado. Las configuraciones relacionadas con el proceso se han restablecido.",
"account.settings.field.name.verified.failure.message.header": "No pudimos verificar tu identidad.",
"account.settings.field.name.verified.failure.message.help.link": "Más información sobre la verificación de ID",
"account.settings.field.name.verified.submitted.message": "Tu solicitud de verificación de identidad ha sido enviada y usualmente se tarda entre 24 a 48 horas para completarse. ",
"account.settings.field.name.verified.submitted.message.certificate": "Cuando la solicitud esté aprobada, la actualización de tu nombre aparecerá en todos los certificados asociados y registros públicos.",
"account.settings.field.name.verified.submitted.message.header": "¡Tu solicitud de cambio de nombre esta por completarse!",
"account.settings.field.email": "Correo electrónico (Ingresar)",
"account.settings.field.email.empty": "Agregar correo electrónico",
"account.settings.field.email.confirmation": "Le enviamos un mensaje de confirmación a {value}. Hacer click en la liga del mensaje para actualizar su correo electrónico.",
"account.settings.field.email.help.text": "Tienes un mensaje de {siteName} y el equipo de curso en esta dirección. ",
"account.settings.field.secondary.email": "Correo electrónico de recuperación",
"account.settings.field.secondary.email.empty": "Agregar un correo electrónico de recuperación",
"account.settings.field.secondary.email.confirmation": "Le enviamos un mensaje de confirmación a {value}. Hacer click en la liga del mensaje para actualizar su correo electrónico.",
"account.settings.email.field.confirmation.header": "Confirmación pendiente",
"account.settings.field.dob": "Año de nacimiento",
"account.settings.field.dob.empty": "Agregar año de nacimiento",
"account.settings.field.year_of_birth.options.empty": "Selecciona año de nacimiento",
"account.settings.field.dob.month": "Mes",
"account.settings.field.dob.year": "Año",
"account.settings.field.dob.form.button": "Por favor confirme su fecha de nacimiento",
"account.settings.field.dob.form.title": "Confirma tu fecha de nacimiento",
"account.settings.field.dob.form.help.text": "Solicitamos información sobre la fecha de nacimiento para ayudarnos a cumplir con nuestras obligaciones legales.",
"account.settings.field.dob.form.success": "Gracias por ingresar la información de su fecha de nacimiento.",
"account.settings.field.month_of_birth.options.empty": "Seleccione un mes de nacimiento",
"account.settingsfield.dob.error.general": "Ha ocurrido un error técnico. Por favor intentalo de nuevo.",
"account.settings.field.country": "País",
"account.settings.field.country.empty": "Agregar país",
"account.settings.field.country.options.empty": "Seleccionar un país",
"account.settings.field.state": "Estado",
"account.settings.field.state.empty": "Añada un estado",
"account.settings.field.state.options.empty": "Seleccionar un estado",
"account.settings.field.site.language": "Idioma del sitio",
"account.settings.field.site.language.help.text": "El idioma que se usará para el sitio. Actualmente solo hay disponibilidad de usar un número limitado de idiomas.",
"account.settings.field.education": "Educación",
"account.settings.field.education.empty": "Agregar un nivel educativo",
"account.settings.field.education.levels.empty": "Seleccionar un nivel educativo",
"account.settings.field.education.levels.p": "Doctorado",
"account.settings.field.education.levels.m": "Master o magíster",
"account.settings.field.education.levels.b": "Pregrado o Licenciatura",
"account.settings.field.education.levels.a": "Grado técnico - tecnológico",
"account.settings.field.education.levels.hs": "Enseñanza secundaria",
"account.settings.field.education.levels.jhs": "Formación media",
"account.settings.field.education.levels.el": "Enseñanza primaria",
"account.settings.field.education.levels.none": "Ninguna educación formal",
"account.settings.field.education.levels.o": "Otra educación",
"account.settings.field.gender": "Género",
"account.settings.field.gender.empty": "Agregar género",
"account.settings.field.gender.options.empty": "Seleccionar el género",
"account.settings.field.gender.options.f": "Femenino",
"account.settings.field.gender.options.m": "Masculino",
"account.settings.field.gender.options.o": "Otro",
"account.settings.field.language.proficiencies": "Idioma hablado",
"account.settings.field.language.proficiencies.empty": "Agregar un idioma hablado",
"account.settings.field.language_proficiencies.options.empty": "Selecciona lenguaje",
"account.settings.field.time.zone": "Zona horaria",
"account.settings.field.time.zone.empty": "Indicar zona horaria",
"account.settings.field.time.zone.description": "Selecciona la zona horaria para exponer las fechas del curso. Si no especificas una zona horaria, las fechas del curso, incluidas las fechas límites de tareas, serán expuestas en la zona horaria local de tu navegador.",
"account.settings.field.time.zone.default": "Por defecto (Zona horaria local)",
"account.settings.field.time.zone.all": "Todas las zonas horarias",
"account.settings.field.time.zone.country": "Zonas horarias",
"account.settings.section.social.media": "Enlaces de redes sociales",
"account.settings.section.social.media.description": "Opcionalmente, conecte sus cuentas personales a los iconos de redes sociales en su perfil de {siteName}.",
"account.settings.field.social.platform.name.linkedin": "LinkedIn",
"account.settings.field.social.platform.name.linkedin.empty": "Agregar perfil de LinkedIn",
"account.settings.jump.nav.delete.account": "Eliminar mi cuenta",
"account.settings.field.social.platform.name.twitter": "Twitter",
"account.settings.field.social.platform.name.twitter.empty": "Agregar perfil de Twitter",
"account.settings.field.social.platform.name.facebook": "Facebook",
"account.settings.field.social.platform.name.facebook.empty": "Agregar perfil de Facebook",
"account.settings.editable.field.action.save": "Guardar",
"account.settings.editable.field.action.cancel": "Cancelar",
"account.settings.editable.field.action.edit": "Editar",
"account.settings.static.field.empty": "No hay valor establecido. Contacte su administrador {enterprise} para hacer cambios.",
"account.settings.static.field.empty.no.admin": "No hay valor establecido.",
"account.settings.field.name.certificate.select": "En caso de ser seleccionado, este nombre aparecerá en tus certificados y registros públicos. ",
"account.settings.field.name.modal.certificate.title": "Escoge un nombre de preferencia para tus certificados y registros públicos.",
"account.settings.field.name.modal.certificate.select": "Selecciona un nombre",
"account.settings.field.name.modal.certificate.option.full": "Nombre completo",
"account.settings.field.name.modal.certificate.option.verified": "Nombre verificado",
"account.settings.field.name.modal.certificate.button.choose": "Escoge un nombre",
"account.settings.coaching.consent.welcome.header": "Empecemos",
"account.settings.coaching.consent.welcome.subheader": "Estamos aquí para ustede desde el inicio hasta el final",
"account.settings.coaching.consent.description": "Los programas de MicroBachelors incluyen entrenamiento que se enfoca en su carrera, educación y cómo logrará resultados a través de la comunicación individual con un profesional experimentado. Si está interesado, proporcione la información a continuación y haga clic en \"Enviar\", y nuestro socio asesor se comunicará con usted por correo electrónico y / o mensaje de texto para ayudarlo a avanzar. Los términos y Condiciones aplican.*",
"account.settings.coaching.consent.text-messaging.disclaimer": "* Los servicios de entrenamiento se incluyen sin costo adicional para los alumnos con números de teléfono de EE. UU. El entrenamiento incluye mensajes de texto recurrentes. Se pueden aplicar tarifas por mensajes y datos. Envía STOP para cancelar la suscripción.",
"account.settings.coaching.consent.accept-coaching": "Registrarse para coaching",
"account.settings.coaching.consent.decline-coaching": "Prefiero no ser contactado con servicios de coaching gratuitos.",
"account.settings.coaching.consent.label.name": "Por favor confirme su nombre",
"account.settings.coaching.consent.label.phone-number": "Ingrese su número de teléfono móvil",
"account.settings.coaching.consent.success.header": "¡Éxito!",
"account.settings.coaching.consent.success.message": "Estás inscrito para coaching. Puedes esperar un mensaje por correo electrónico o SMS en los próximos días.",
"account.settings.coaching.consent.success.continue": "Iniciar mi curso",
"account.settings.coaching.managed.support": "soporte",
"account.settings.coaching.managed.alert": "{ManagerTitle} administra su Nombre. Póngase en contacto con su administrador para obtener ayuda.",
"account.settings.field.phone_number": "Teléfono",
"account.settings.field.phone_number.empty": "Añadir un número de teléfono",
"account.settings.field.coaching_consent": "Consentimiento de coaching",
"account.settings.field.coaching_consent.tooltip": "Los programas de MicroBachelors incluyen entrenamiento basado en mensajes de texto que lo ayuda a emparejar experiencias educativas con sus objetivos profesionales a través de asesoramiento personalizado. Los servicios de entrenamiento se incluyen sin costo adicional y están disponibles para estudiantes con números de teléfono móvil de EE. UU. Se aplican tarifas de mensajería estándar. Envíe \"STOP\" en cualquier momento para cancelar la suscripción a los mensajes.",
"account.settings.field.coaching_consent.error": "Se requiere un número de teléfono válido de EE. UU. Para optar por el coaching",
"account.settings.delete.account.before.proceeding": "Antes de continuar, por favor {actionLink}.",
"account.settings.delete.account.header": "Eliminar mi cuenta",
"account.settings.delete.account.subheader": "¡Sentimos que te vayas!",
"account.settings.delete.account.text.1": "Para tener en cuenta: La eliminación de su cuenta y sus datos personales es permanente y no se puede deshacer. {siteName} no podrá recuperar tu cuenta o la información que sea eliminada.",
"account.settings.delete.account.text.2": "Una véz tu cuenta haya sido eliminada, no podrás usarla para tomar cursos en {siteName}. ",
"account.settings.delete.account.text.2.edX": "Una vez su cuenta haya sido eliminada, no la podrá usar para tomar cursos en la app de edX, edx.org o en cualquier otro sitio administrado por edX. Esto incluye el acceso a edx.org desde el sistema de su empleador o universidad y el acceso a páginas privadas ofrecidas por MIT Open Learning, Wharton Executive Education y Harvard Medical School.",
"account.settings.delete.account.text.3.link": "Sigue estas instrucciones para imprimir o descargar un certificado. ",
"account.settings.delete.account.text.warning": "Atención: la eliminación de su cuenta es permanente. Por favor lea el previo aviso cautelosamente antes de proceder, ya que esto es una acción irreversible, y no podrá usar el mismo correo electrónico en {siteName}.",
"account.settings.delete.account.text.change.instead": "En lugar de eso, ¿quieres cambiar tu correo electrónico, nombre o contraseña?",
"account.settings.delete.account.button": "Eliminar mi cuenta",
"account.settings.delete.account.please.activate": "activar su cuenta",
"account.settings.delete.account.please.confirm": "Confirma tu cuenta",
"account.settings.delete.account.please.unlink": "Desvincular todas las cuentas de redes sociales.",
"account.settings.delete.account.modal.header": "¿Está seguro?",
"account.settings.delete.account.modal.text.1": "Has seleccionado la opción ''Eliminar mi cuenta''. Ten en cuenta que la eliminación de tu cuenta e información personal es permanente y no puede revertirse. {siteName} no será capaz de recuperar tu cuenta o información una vez esta sea eliminada. ",
"account.settings.delete.account.modal.text.2": "Si aceptas proceder, ya no podrás usar esta cuenta para tomar cursos en {siteName}.",
"account.settings.delete.account.modal.text.2.edX": "Si procedes, no será posible usar esta cuenta para tomar cursos ni en la aplicación móvil de edX, ni en edx.org, ni en cualquier otro sitio hospedado por edX. Esto incluye el acceso a edx.org desde el sistema de tu empleador o universidad, y el acceso a sitios privados ofrecidos por MIT Open Learning, Wharton Executive Education, y Harvard Medical School.",
"account.settings.delete.account.modal.enter.password": "Si deseas continuar y eliminar tu cuenta, por favor introduce la contraseña de tu cuenta:",
"account.settings.delete.account.modal.confirm.delete": "Si, Eliminar",
"account.settings.delete.account.modal.confirm.cancel": "Cancelar",
"account.settings.delete.account.error.unable.to.delete": "No es posible eliminar esta cuenta",
"account.settings.delete.account.error.no.password": "Se requiere una contraseña",
"account.settings.delete.account.error.invalid.password": "Contraseña incorrecta",
"account.settings.delete.account.error.unable.to.delete.details": "Ocurrió un error al procesar tu solicitud. Por favor, intente nuevamente más tarde.",
"account.settings.delete.account.modal.after.header": "¡Sentimos que te vayas! Tu cuenta será eliminada en breve.",
"account.settings.delete.account.modal.after.text": "La eliminación de cuenta, incluyendo la eliminación de las listas de correo electrónico, puede tardar unas semanas en procesarse totalmente en nuestro sistema. Si quieres renunciar a recibir correos antes de que la eliminación se haya completado, por favor date de baja mediante el enlace que aparece al final de los correos.",
"account.settings.delete.account.modal.after.button": "Cerrar",
"account.settings.delete.account.text.3.edX": "También podrás perder el acceso a certificados verificados y a otras credenciales del programa como los certificados MicroMasters. Puedes hacer una copia de estos registros antes de proceder con la eliminación. {actionLink}.",
"account.settings.delete.account.text.3": "También podrás perder el acceso a certificados verificados y a otras credenciales del programa. Puedes hacer una copia de estos registros antes de proceder con la eliminación. ",
"account.settings.message.demographics.service.issue": "Ocurrió un error al intentar recuperar o guardar la información de tu cuenta. Por favor inténtalo más tarde.",
"account.settings.field.demographics.gender": "Identidad de género",
"account.settings.field.demographics.gender.empty": "Añade identidad de género",
"account.settings.field.demographics.gender.options.empty": "Selecciona una identidad de género",
"account.settings.field.demographics.gender_description": "Descripción de identidad de género",
"account.settings.field.demographics.gender_description.empty": "Ingresa descripción",
"account.settings.field.demographics.ethnicity": "Identidad étnica/raza",
"account.settings.field.demographics.ethnicity.empty": "Añade identidad étnica/raza",
"account.settings.field.demographics.ethnicity.options.empty": "Selecciona todas las que apliquen",
"account.settings.field.demographics.income": "Ingreso familiar",
"account.settings.field.demographics.income.empty": "Añade ingreso familiar",
"account.settings.field.demographics.income.options.empty": "Selecciona un rango de ingreso familiar",
"account.settings.field.demographics.military_history": "Estatus militar en EE.UU.",
"account.settings.field.demographics.military_history.empty": "Añade estatus militar",
"account.settings.field.demographics.military_history.options.empty": "Selecciona estatus militar",
"account.settings.field.demographics.learner_education_level": "Tu nivel educacional",
"account.settings.field.demographics.learner_education_level.empty": "Añade nivel educacional",
"account.settings.field.demographics.parent_education_level": "Nivel educacional de padres/tutores",
"account.settings.field.demographics.parent_education_level.empty": "Añade nivel educacional",
"account.settings.field.demographics.education_level.options.empty": "Selecciona nivel educacional",
"account.settings.field.demographics.work_status": "Estatus laboral",
"account.settings.field.demographics.work_status.empty": "Añade estatus laboral",
"account.settings.field.demographics.work_status.options.empty": "Selecciona estatus laboral",
"account.settings.field.demographics.work_status_description": "Descripción estatus laboral",
"account.settings.field.demographics.work_status_description.empty": "Ingresa descripción",
"account.settings.field.demographics.current_work_sector": "Área profesional actual",
"account.settings.field.demographics.current_work_sector.empty": "Añade área profesional",
"account.settings.field.demographics.future_work_sector": "Área profesional futura",
"account.settings.field.demographics.future_work_sector.empty": "Añade área profesional",
"account.settings.field.demographics.work_sector.options.empty": "Selecciona área profesional",
"account.settings.section.demographics.why": "¿Por qué {siteName} recauda esta información?",
"account.settings.name.change.title.id": "Este cambio de nombre requiere de verificación de identidad.",
"account.settings.name.change.title.begin": "Antes de empezar",
"account.settings.name.change.warning.one": "Atención: esta acción actualizará el nombre que aparece en todos los certificados obtenidos a través de esta cuenta en el pasado y en aquellos en que actualmente estás obteniendo o que adquirirás en el futuro.",
"account.settings.name.change.warning.two": "Esta acción no podrá revertirse sin antes verificar tu identidad.",
"account.settings.name.change.id.name.label": "Ingrese su nombre tal como aparece en su tarjeta de identificación vigente de estudiante, trabajo o emitida por el gobierno.",
"account.settings.name.change.id.name.placeholder": "Ingrese el nombre en su identificación con foto",
"account.settings.name.change.error.valid.name": "Por favor ingresa un nombre valido.",
"account.settings.name.change.error.general": "Ha ocurrido un error técnico. Por favor intentalo de nuevo.",
"account.settings.name.change.continue": "Continuar",
"account.settings.name.change.cancel": "Cancelar",
"error.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.",
"account.settings.editable.field.password.reset.button.confirmation.support.link": "soporte técnico",
"account.settings.editable.field.password.reset.button.confirmation": "Hemos mandado un mensaje a {email}. Haz clic en el enlace en el mensaje para restablecer tu contraseña. ¿No recibiste el mensaje? Contáctate con {technicalSupportLink}.",
"account.settings.editable.field.password.reset.button": "Restablecer contraseña",
"account.settings.editable.field.password.reset.button.forbidden": "Su solicitud anterior está en progreso, intente nuevamente en unos momentos.",
"account.settings.editable.field.password.reset.label": "Contraseña",
"account.settings.sso.link.account": "Iniciar sesión con {name}",
"account.settings.sso.account.connected": "Vinculado",
"account.settings.sso.account.disconnect.error": "Hubo un problema al desconectar esta Cuenta. Si el problema persiste, contacte soporte.",
"account.settings.sso.unlink.account": "Desvincular la cuenta de {accountName} ",
"account.settings.sso.no.providers": "No se pueden vincular cuentas en este momento.",
"account.page.title": "Cuenta | {siteName}",
"id.verification.access.blocked.denied": "No podemos verificar tu identidad en este momento. Si aún no has activado tu cuenta, comprueba en tu carpeta de correo no deseado el correo de activación de {email}.",
"id.verification.next": "Siguiente",
"id.verification.support": "soporte",
"id.verification.example.card.alt": "Ejemplo de un documento de identidad válido con foto y nombre completo.",
"id.verification.requirements.title": "Requerimientos de verificación por foto",
"id.verification.requirements.description": "Para completa la verificación de foto, necesitarás lo siguiente:",
"id.verification.requirements.card.device.title": "Dispositivo con cámara",
"id.verification.requirements.card.device.allow": "Permitir",
"id.verification.requirements.card.id.title": "Tarjeta de identificación con foto",
"id.verification.requirements.card.id.text": "Necesitas una tarjeta de identificación válida que contenga tu nombre completo y foto, similar a una licencia de conducir o pasaporte.",
"id.verification.privacy.title": "Información de privacidad",
"id.verification.privacy.need.photo.question": "¿Por qué {siteName} necesita mi foto?",
"id.verification.privacy.need.photo.answer": "Utilizamos tus fotos de verificación para confirmar tu identidad y garantizar la validez de tu certificado.",
"id.verification.privacy.do.with.photo.question": "¿Qué hace {siteName} con esta foto?",
"id.verification.privacy.do.with.photo.answer": "Encriptamos de forma segura tu foto y la enviamos a nuestro servicio de autorización para su revisión. Tu foto e información no se guardan ni se ven en ninguna parte de {siteName} después de que se completa el proceso de verificación.",
"id.verification.access.blocked.title": "Verificación de identidad",
"id.verification.access.blocked.enrollment": "Actualmente, no estás inscrito en un curso que requiera verificación de identidad.",
"id.verification.access.blocked.pending": "Ya has enviado tu información de verificación de identidad. Recibirás un mensaje en tu panel principal cuando el proceso de verificación esté completado (usualmente dentro de los 5 días).",
"id.verification.photo.take": "Tomar la foto",
"id.verification.photo.retake": "¿Tomar nuevamente la foto?",
"id.verification.photo.enable.detection": "Habilitar la detección de rostro",
"id.verification.photo.enable.detection.portrait.help.text": "Si está marcada, aparecerá un cuadro alrededor de tu cara. Tu rostro se puede ver claramente si el cuadro que lo rodea es azul. Si Tu cara no está en una buena posición o es indetectable, el cuadro será rojo.",
"id.verification.photo.enable.detection.id.help.text": "Si está marcada, aparecerá una casilla alrededor de la cara de tu documento de identificación. La cara se puede ver claramente si la caja que la rodea es azul. Si la cara no está en una buena posición o es indetectable, el cuadro será rojo.",
"id.verification.photo.feedback.correct": "La cara está en una buena posición.",
"id.verification.photo.feedback.two.faces": "Más de un rostro detectado.",
"id.verification.photo.feedback.no.faces": "No se detectó el rostro.",
"id.verification.photo.feedback.top.left": "Posición incorrecta. Arriba a la izquierda.",
"id.verification.photo.feedback.top.center": "Posición incorrecta. Centro Superior.",
"id.verification.photo.feedback.top.right": "Posición incorrecta. Parte superior derecha.",
"id.verification.photo.feedback.center.left": "Posición incorrecta. Centro izquierda.",
"id.verification.photo.feedback.center.center": "Posición incorrecta. Demasiado cerca de la cámara.",
"id.verification.photo.feedback.center.right": "Posición incorrecta. Centro derecha.",
"id.verification.photo.feedback.bottom.left": "Posición incorrecta. Abajo a la izquierda.",
"id.verification.photo.feedback.bottom.center": "Posición incorrecta. Parte inferior central.",
"id.verification.photo.feedback.bottom.right": "Posición incorrecta. Abajo a la derecha.",
"id.verification.camera.access.title": "Permisos de la cámara",
"id.verification.camera.access.title.success": "Acceso a la cámara habilitado",
"id.verification.camera.access.title.failed": "Acceso a la cámara no habilitado",
"id.verification.camera.access.click.allow": "Por favor asegúrate de hacer clic en \"Permitir\"",
"id.verification.camera.access.enable": "Habilitar cámara",
"id.verification.camera.access.problems": "¿Tienes problemas?",
"id.verification.camera.access.skip": "Omitir y cargar un archivo de imagen",
"id.verification.camera.access.success": "Parece que tu cámara está funcionando y está lista.",
"id.verification.camera.access.failure": "Parece que no podemos acceder a tu cámara. Deberás cargar archivos de imagen de tu rostro y tu identificación con foto.",
"id.verification.camera.access.failure.temporary": "Parece que no podemos acceder a tu cámara. Verifica que tu cámara web esté conectada y que permitiste que tu navegador acceda a ella.",
"id.verification.camera.access.failure.temporary.chrome": "Para habilitar el acceso a la cámara en Chrome:",
"id.verification.camera.access.failure.temporary.chrome.step1": "Abrir Chrome.",
"id.verification.camera.access.failure.temporary.chrome.step2": "Navega a Más > Configuración.",
"id.verification.camera.access.failure.temporary.chrome.step2.windows": "Para Windows: Alt + F, Alt + E o F10 seguido de la barra espaciadora",
"id.verification.camera.access.failure.temporary.chrome.step2.mac": "Para Mac: Comando +,",
"id.verification.camera.access.failure.temporary.chrome.step3": "En la pestaña \"Privacidad y seguridad\", selecciona \"Configuración del sitio\" y luego \"Cámara.\"",
"id.verification.camera.access.failure.temporary.chrome.step4": "En \"Bloqueado\", busca \"edx.org\" y selecciónalo.",
"id.verification.camera.access.failure.temporary.chrome.step5": "En la sección \"Permisos\", actualiza los permisos de la cámara a \"Permitir\".",
"id.verification.camera.access.failure.temporary.ie11": "Para habilitar el acceso a la cámara en Internet Explorer:",
"id.verification.camera.access.failure.temporary.ie11.step1": "Abre el Administrador de configuración de Flash Player navegando a Configuración de Windows > Panel de control > Flash Player.",
"id.verification.camera.access.failure.temporary.ie11.step2": "Selecciona la pestaña \"Cámara y micrófono,\" y luego selecciona el botón \"Configuración de cámara y micrófono por sitio.\"",
"id.verification.camera.access.failure.temporary.ie11.step3": "Elige \"edx.org\" de la lista de sitios web y cambia los permisos seleccionando \"Permitir\" en el menú desplegable.",
"id.verification.camera.access.failure.temporary.firefox": "Para habilitar el acceso a la cámara en Firefox:",
"id.verification.camera.access.failure.temporary.firefox.step1": "Abrir Firefox.",
"id.verification.camera.access.failure.temporary.firefox.step2": "Coloca \"about:preferences\" en la barra del URL.",
"id.verification.camera.access.failure.temporary.firefox.step3": "Selecciona la pestaña \"Privacidad y seguridad\" y navega hasta la sección \"Permisos.\"",
"id.verification.camera.access.failure.temporary.firefox.step4": "Junto a \"Cámara,\" selecciona el botón \"Configuración...\"",
"id.verification.camera.access.failure.temporary.firefox.step5": "En la barra de búsqueda, ingresa \"edx.org\".",
"id.verification.camera.access.failure.temporary.firefox.step6": "En la columna de estado de \"edx.org\", selecciona \"Permitir\" en el menú desplegable.",
"id.verification.camera.access.failure.temporary.firefox.step7": "Selecciona \"Guardar cambios.\"",
"id.verification.camera.access.failure.temporary.safari": "Para habilitar el acceso a la cámara en Safari:",
"id.verification.camera.access.failure.temporary.safari.step1": "Abrir Safari.",
"id.verification.camera.access.failure.temporary.safari.step2": "Haz clic en el menú de la aplicación Safari y luego selecciona \"Preferencias\". También puedes utilizar Command +, como método abreviado de teclado.",
"id.verification.camera.access.failure.temporary.safari.step3": "Selecciona la pestaña \"Sitios web\" y luego selecciona \"Cámara\".",
"id.verification.camera.access.failure.temporary.safari.step4": "Selecciona \"edx.org\" y cambia los permisos de la cámara a \"Permitir.\"",
"id.verification.camera.access.failure.unsupported": "Parece que tu navegar no soporta el acceso a la cámara.",
"id.verification.camera.access.failure.unsupported.chrome.explanation": "El navegador de Chrome actualmente no soporta el acceso a la cámara en dispositivos iOS, como iPhones y iPads.",
"id.verification.camera.access.failure.unsupported.instructions": "Por favor utilice otro navegador para completar la verificación de identidad.",
"id.verification.photo.tips.title": "Consejos útiles de fotos",
"id.verification.photo.tips.description": "A continuación, necesitaremos que tomes una foto de tu rostro. Por favor, revisa los siguientes consejos útiles.",
"id.verification.photo.tips.list.title": "Consejos para fotos",
"id.verification.photo.tips.list.description": "Para tomar la foto correctamente, asegúrate de: ",
"id.verification.photo.tips.list.well.lit": "El rostro esté bien iluminado",
"id.verification.photo.tips.list.inside.frame": "Tu cara está completamente dentro del marco de la foto.",
"id.verification.portrait.photo.title.camera": "Toma una foto de ti mismo",
"id.verification.portrait.photo.instructions.camera": "Cuando tu rostro esté en posición, usa el botón Tomar foto a continuación para tomar tu foto.",
"id.verification.camera.help.sight.question": "¿Qué pasa si no puedo ver la imagen de la cámara o si no puedo ver mi foto para determinar qué lado es visible?",
"id.verification.camera.help.sight.answer.portrait": "Es posible que puedas completar el procedimiento de captura de imágenes sin ayuda, pero es posible que necesites un par de intentos de envío para que la cámara se coloque correctamente. La posición óptima de la cámara varía con cada computadora, pero generalmente la mejor distancia para una foto de rostro es aproximadamente a 12 a 18 pulgadas (30 a 45 centímetros) de la cámara, con la cabeza centrada en relación con la pantalla de la computadora. Si las fotos que envías son rechazadas, intenta mover la computadora o la orientación de la cámara para cambiar el ángulo de iluminación.",
"id.verification.camera.help.sight.answer.id": "Es posible que puedas completar el procedimiento de captura de imágenes sin ayuda, pero es posible que necesites un par de intentos de envío para que la cámara se coloque correctamente. El posicionamiento óptimo de la cámara varía con cada computadora pero, generalmente, la mejor distancia para una foto de un documento de identificación es a 8 a 12 pulgadas (20 a 30 centímetros) de la cámara, con el documento de identificación centrado en relación con la cámara. Si las fotos que envías son rechazadas, intenta mover la computadora o la orientación de la cámara para cambiar el ángulo de iluminación. La razón más común de rechazo es la imposibilidad de leer el texto del documento de identidad.",
"id.verification.camera.help.difficulty.question.portrait": "¿Qué sucede si tengo dificultades para mantener la cabeza en posición con respecto a la cámara?",
"id.verification.camera.help.difficulty.question.id": "¿Qué sucede si tengo dificultades para mantener mi identificación en posición con respecto a la cámara?",
"id.verification.camera.help.difficulty.answer": "Si requieres de asistencia para cargar una foto, contacta el equipo de soporte de {siteName} para sugerencias adicionales.",
"id.verification.id.photo.unclear.question": "¿No es clara la foto de tu tarjeta de ID ó es muy borrosa?",
"id.verification.id.tips.title": "Tips de ayuda para tarjetas de identificación",
"id.verification.id.tips.description": "Después, necesitaremos que tomes una foto de una tarjeta de ID válida que tengas en la que incluya tu nombre completo y foto, como una licencia de conducción o un pasaporte. Por favor ten tú ID lista.",
"id.verification.id.tips.list.well.lit": "Tu tarjeta de identificación está bien iluminada.",
"id.verification.id.tips.list.clear": "Asegúrate de que puedes ver tu foto y leer claramente tu nombre.",
"id.verification.id.photo.title.camera": "Toma una foto de tu tarjeta de identificación",
"id.verification.id.photo.title.upload": "Sube una foto de tu tarjeta de identificación",
"id.verification.id.photo.preview.alt": "Previsualización de Foto ID",
"id.verification.id.photo.instructions.camera": "Cuando tú ID este en posición, utiliza el botón de tomar foto que se encuentra debajo para proceder a tomar tu foto. Por favor usa un pasaporte, licencia de conducción, u otra tarjeta de identificación que incluya tu nombre completo y una foto de tu rostro.",
"id.verification.id.photo.instructions.upload": "Por favor sube una foto de tu identificación. Asegurate de que todo el ID encaje dentro de el marco y que este bien iluminado. El tamaño del archivo debe ser por debajo de 10 MB. Los formatos soportados son: ",
"id.verification.id.photo.instructions.upload.error.invalidFileType": "El archivo que has seleccionado no cumple con el tipo de imágenes soportadas. Por favor escoge entre los siguientes formatos:",
"id.verification.id.photo.instructions.upload.error.fileTooLarge": "El archivo que has seleccionado es demasiado grande. Vuelve a intentarlo con un archivo de menos de 10 MB.",
"id.verification.name.check.title": "Revisa nuevamente tu nombre",
"id.verification.name.check.instructions": "¿El nombre a continuación coincide con el nombre en su identificación con foto? De lo contrario, actualice el nombre a continuación para que coincida con su identificación con foto.",
"id.verification.name.check.mismatch.information": "Si el nombre a continuación no coincide con su identificación con foto, se denegará su verificación de identidad.",
"id.verification.name.error": "Ingrese su nombre tal como aparece en su identificación con foto.",
"id.verification.account.name.warning.prefix": "Ten en cuenta:",
"id.verification.account.name.settings": "Configuración de cuenta",
"id.verification.name.label": "Nombre",
"id.verification.account.name.photo.alt": "Foto de tu identificación a enviar.",
"id.verification.review.title": "Revisar tus fotos",
"id.verification.review.description": "Asegúrate de que podamos verificar tu identidad con las imágenes y la información suministradas.",
"id.verification.review.portrait.label": "Tu Retrato",
"id.verification.review.portrait.alt": "Foto de tu rostro a enviar.",
"id.verification.review.portrait.retake": "Retomar Foto de Retrato",
"id.verification.review.id.label": "Tú tarjeta de identificación",
"id.verification.review.id.alt": "Foto de tu tarjeta de identificación para ser enviada.",
"id.verification.review.id.retake": "Retomar Foto de identificación",
"id.verification.review.confirm": "Enviar",
"id.verification.submission.alert.error.face": "Se requiere una foto de tu rostro. Vuelve a tomar tu foto de retrato.",
"id.verification.submission.alert.error.id": "Se requiere una foto de tu documento de ID. Vuelve a tomar tu foto de ID.",
"id.verification.submission.alert.error.name": "Se requiere un nombre de cuenta válido. Actualiza el nombre de tu cuenta para que coincida con el nombre que figura en tu ID.",
"id.verification.submission.alert.error.unsupported": "Uno o más de los siguientes archivos que has subido se encuentran en un formato no soportado. Por favor escoge de los siguientes formatos:",
"id.verification.review.error": "Página de soporte de {siteName}",
"id.verification.submitted.title": "Verificación de identidad en progreso.",
"id.verification.submitted.text": "Hemos recibido su información y estamos verificando su identidad. Se le notificará cuando se complete el proceso de verificación (generalmente dentro de los 5 días). Mientras tanto, aún puede acceder a todo el contenido del curso disponible.",
"id.verification.return.dashboard": "Volver al panel principal",
"id.verification.return.course": "Regresar al curso",
"id.verification.return.generic": "Regresar",
"id.verification.photo.upload.help.title": "Cargar una imágen en vez",
"id.verification.photo.camera.help.title": "Usar la cámara en vez",
"id.verification.photo.upload.help.text": "Si estás presentando problemas usando el capturador de fotos, es posible que prefieras subir una foto en vez. Para subir una foto, has clic en el botón a continuación ",
"id.verification.photo.camera.help.text": "Si estás presentando problemas subiendo una foto, es posible que prefieras usar la cámara en vez. Para usar una cámara, has clic en el botón a continuación.",
"id.verification.upload.help.button": "Cambia a modo de carga",
"id.verification.camera.help.button": "Cambia a modo de cámara",
"id.verification.request.camera.access.instructions": "Para tomar una foto con tu cámara web, es posible que recibas un aviso del navegador para acceder a tu cámara. {clickAllow}",
"id.verification.requirements.account.managed.alert": "La configuración de tu perfil es administrada por {managerTitle}. Por lo tanto si el nombre en tu ID de foto coincide con tu nombre de cuenta por favor ponte en contacto con tu administrador de {profileDataManager} o con {soporte} para solicitar ayuda antes de completar el proceso de verificación de foto.",
"id.verification.requirements.card.device.text": "Necesitas un dispositivo que tenga una cámara. Si has recibido un aviso del navegador para habilitar acceso a tu cámara, por favor asegúrate de seleccionar [allow].",
"id.verification.account.name.summary.alert": "La configuración de tu perfil es administrada por {managerTitle}. Por lo tanto si el nombre en tu ID de foto coincide con tu nombre de cuenta por favor ponte en contacto con tu administrador de {profileDataManager} o con {soporte} para solicitar ayuda.",
"idv.submission.alert.error": "\n Se produjo un error técnico al intentar enviar la verificación de ID.\n Es posible que sea una cuestión temporal, así que inténtalo de nuevo en unos minutos.\n Si el problema continúa, dirígete a {support_link} para obtener ayuda.\n ",
"id.verification.account.name.edit": "Editar {sr}"
}

View File

@@ -1,359 +0,0 @@
{
"account.settings.message.duplicate.tpa.provider": "Le compte {provider} que vous avez sélectionné est déjà lié à un autre compte {siteName}.",
"account.settings.message.managed.settings": "Vos paramètres de profile sont gérés par {managerTitle}. Contactez votre administrateur ou {support} en cas de besoin.",
"account.settings.message.managed.settings.support": "support",
"account.settings.page.heading": "Paramètres du compte",
"account.settings.loading.message": "Chargement...",
"account.settings.loading.error": "Erreur : {error}",
"account.settings.banner.beta.language": "Vous avez réglé votre langue sur {beta_language}, qui n'est actuellement pas entièrement traduite. Vous pouvez nous aider à traduire complètement cette langue en rejoignant la communauté Transifex et en ajoutant des traductions de l'anglais pour les apprenants qui parlent {beta_language}.",
"account.settings.banner.beta.language.action.switch.back": "Revenir au {previous_language}",
"account.settings.banner.beta.language.action.help.translate": "Aidez-nous à traduire en {beta_language}",
"account.settings.section.account.information": "Information du compte",
"account.settings.section.account.information.description": "Ces paramètres comprennent des informations de base à propos de votre compte.",
"account.settings.section.profile.information": "Informations de profil",
"account.settings.section.demographics.information": "Informations optionnelles",
"account.settings.section.site.preferences": "Préférences de site",
"account.settings.section.linked.accounts": "Comptes liés",
"account.settings.section.linked.accounts.description": "Vous pouvez associer vos comptes d'identité pour simplifier la connexion à {siteName}.",
"account.settings.field.username": "Nom dutilisateur",
"account.settings.field.username.help.text": "Le nom qui vous identifie sur {siteName}. Vous ne pouvez pas changer votre nom d'utilisateur.",
"account.settings.field.full.name": "Nom complet",
"account.settings.field.full.name.empty": "Ajouter un nom",
"account.settings.field.full.name.help.text": "Le nom qui apparaîtra sur vos certificats et dans le cadre de toute vérification d'identité.",
"account.settings.field.full.name.help.text.default": "Le nom qui apparaît sur votre profile public.",
"account.settings.field.full.name.help.text.default.certificate": "Ce nom va apparaître sur vos attestations et dossiers publics.",
"account.settings.field.name.verified": "Nom vérifié",
"account.settings.field.name.verified.help.text.verified": "Ce nom a été vérifié par une pièce d&#39;identité avec photo.",
"account.settings.field.name.verified.help.text.verified.proctored": "Ce nom a été vérifié par la surveillance.",
"account.settings.field.name.verified.help.text.verified.certificate": "Ce nom a été vérifié par une pièce d&#39;identité avec photo et est sélectionné pour apparaître sur vos certificats et vos dossiers publics.",
"account.settings.field.name.verified.help.text.verified.proctored.certificate": "Ce nom a été vérifié par la surveillance et est sélectionné pour apparaître sur vos certificats et vos enregistrements publics.",
"account.settings.field.name.verified.help.text.submitted": "La vérification a été soumise. Cela prend généralement 48 heures ou moins. Le nom vérifié ne peut pas être modifié pour le moment.",
"account.settings.field.name.verified.help.text.submitted.proctored": "Votre examen surveillé a été soumis. Le nom vérifié ne peut pas être modifié pour le moment. Veuillez réessayer dans 2 à 5 jours.",
"account.settings.field.name.verified.help.text.submitted.certificate": "Une fois la vérification d'identité réussie, ce nom apparaîtra sur vos attestations et vos dossiers publics. Le nom complet ne peut pas être modifié pour le moment.",
"account.settings.field.name.verified.help.text.submitted.proctored.certificate": "Une fois que votre examen surveillé a réussi l&#39;examen, ce nom apparaîtra sur votre certificat et vos dossiers publics. Le nom vérifié ne peut pas être modifié pour le moment.",
"account.settings.field.name.verified.verification.help": "Entrez votre nom tel qu&#39;il apparaît sur votre carte d&#39;étudiant, de travail ou d&#39;identité émise par le gouvernement.",
"account.settings.field.full.name.help.text.submitted": "La vérification a été soumise. Cela prend généralement 48 heures ou moins. Le nom vérifié ne peut pas être modifié pour le moment.",
"account.settings.field.full.name.help.text.submitted.proctored": "Votre examen surveillé a été soumis. Le nom complet ne peut pas être modifié pour le moment. Veuillez réessayer dans 2 à 5 jours.",
"account.settings.field.full.name.help.text.submitted.certificate": "Une fois la vérification d'identité réussie, ce nom apparaîtra sur vos attestations et vos dossiers publics. Le nom complet ne peut pas être modifié pour le moment.",
"account.settings.field.full.name.help.text.submitted.proctored.certificate": "Une fois que votre examen surveillé a réussi l&#39;examen, ce nom apparaîtra sur vos certificats et vos dossiers publics. Le nom complet ne peut pas être modifié pour le moment.",
"account.settings.field.name.verified.success.message": "Votre demande de vérification d'identité a été complétée avec succès. Vous avez maintenant la possibilité de sélectionner le nom que vous préférez voir apparaître sur vos attestations et documents publics.",
"account.settings.field.name.verified.success.message.header": "Votre demande de changement de nom est terminée!",
"account.settings.field.name.verified.failure.message": "Votre dernière tentative de vérification d'identité n'a pas abouti. Les paramètres du compte correspondant ont été restaurés.",
"account.settings.field.name.verified.failure.message.header": "Nous n'avons pas pu vérifier votre identité.",
"account.settings.field.name.verified.failure.message.help.link": "En savoir plus sur la vérification d'identité",
"account.settings.field.name.verified.submitted.message": "Votre demande de vérification d'identité a bien été envoyée et prend généralement entre 24 et 48 heures afin d'être validée.",
"account.settings.field.name.verified.submitted.message.certificate": "Lorsque votre demande est approuvée, votre nouveau nom apparaîtra sur tous les certificats associés et les enregistrements publics.",
"account.settings.field.name.verified.submitted.message.header": "Votre demande de changement de nom est presque terminée!",
"account.settings.field.email": "Adresse e-mail (Connexion)",
"account.settings.field.email.empty": "Ajouter l'adresse e-mail",
"account.settings.field.email.confirmation": "Un message de confirmation a été envoyé à {value}. Cliquer le lien dans le message afin de mettre à jour votre adresse email.",
"account.settings.field.email.help.text": "Vous recevrez des messages de {siteName} et des équipes pédagogiques à cette adresse.",
"account.settings.field.secondary.email": "Adresse électronique de récupération",
"account.settings.field.secondary.email.empty": "Ajouter une adresse électronique de récupération",
"account.settings.field.secondary.email.confirmation": "Un message de confirmation a été envoyé à {value}. Cliquer le lien dans le message afin de mettre à jour votre adresse email.",
"account.settings.email.field.confirmation.header": "En attente de confirmation",
"account.settings.field.dob": "Année de naissance",
"account.settings.field.dob.empty": "Ajouter année de naissance",
"account.settings.field.year_of_birth.options.empty": "Sélectionnez une année de naissance",
"account.settings.field.dob.month": "Month",
"account.settings.field.dob.year": "Year",
"account.settings.field.dob.form.button": "Please confirm your date of birth",
"account.settings.field.dob.form.title": "Confirm your date of birth",
"account.settings.field.dob.form.help.text": "We ask for birth date information to help us comply with our legal obligations.",
"account.settings.field.dob.form.success": "Thank you for entering your birth date information.",
"account.settings.field.month_of_birth.options.empty": "Select a month of birth",
"account.settingsfield.dob.error.general": "A technical error occurred. Please try again.",
"account.settings.field.country": "Pays",
"account.settings.field.country.empty": "Ajouter un pays",
"account.settings.field.country.options.empty": "Sélectionnez un pays",
"account.settings.field.state": "État",
"account.settings.field.state.empty": "Ajouter un état",
"account.settings.field.state.options.empty": "Choisir un état",
"account.settings.field.site.language": "Langue du site",
"account.settings.field.site.language.help.text": "La langue utilisée au travers du site. Le site est actuellement disponible dans un nombre limité de langues.",
"account.settings.field.education": "Education",
"account.settings.field.education.empty": "Ajouter le niveau d'éducation",
"account.settings.field.education.levels.empty": "Sélectionnez un niveau d'éducation",
"account.settings.field.education.levels.p": "Doctorat",
"account.settings.field.education.levels.m": "Master ou diplôme professionnel",
"account.settings.field.education.levels.b": "Diplôme de licence",
"account.settings.field.education.levels.a": "Grade de l'associé",
"account.settings.field.education.levels.hs": "Lycée / enseignement secondaire",
"account.settings.field.education.levels.jhs": "Collège / enseignement secondaire inférieur",
"account.settings.field.education.levels.el": "Enseignement primaire",
"account.settings.field.education.levels.none": "Sans diplôme",
"account.settings.field.education.levels.o": "Autre niveau d'étude",
"account.settings.field.gender": "Genre",
"account.settings.field.gender.empty": "Ajouter le genre",
"account.settings.field.gender.options.empty": "Sélectionner un genre",
"account.settings.field.gender.options.f": "Femme",
"account.settings.field.gender.options.m": "Homme",
"account.settings.field.gender.options.o": "Autre",
"account.settings.field.language.proficiencies": "Langue parlée",
"account.settings.field.language.proficiencies.empty": "Ajouter une langue parlée",
"account.settings.field.language_proficiencies.options.empty": "Sélectionnez une langue",
"account.settings.field.time.zone": "Fuseau horaire",
"account.settings.field.time.zone.empty": "Définir le fuseau horaire",
"account.settings.field.time.zone.description": "Sélectionnez le fuseau horaire pour l'affichage des dates de cours. Si vous n'indiquez aucun fuseau horaire, les dates de cours, y compris les échéances de devoirs, seront affichés en fonction du fuseau horaire local de votre navigateur. ",
"account.settings.field.time.zone.default": "Défaut (fuseau horaire local)",
"account.settings.field.time.zone.all": "Tous les fuseaux horaires",
"account.settings.field.time.zone.country": "Fuseaux horaires des pays",
"account.settings.section.social.media": "Liens vers les réseaux sociaux",
"account.settings.section.social.media.description": "Optionnellement, liez vos comptes personnels aux icônes des médias sociaux sur votre profil {siteName}.",
"account.settings.field.social.platform.name.linkedin": "LinkedIn",
"account.settings.field.social.platform.name.linkedin.empty": "Ajouter un profil LinkedIn",
"account.settings.jump.nav.delete.account": "Supprimer mon compte",
"account.settings.field.social.platform.name.twitter": "Twitter",
"account.settings.field.social.platform.name.twitter.empty": "Ajouter un profil Twitter",
"account.settings.field.social.platform.name.facebook": "Facebook",
"account.settings.field.social.platform.name.facebook.empty": "Ajouter un profil Facebook",
"account.settings.editable.field.action.save": "Enregistrer",
"account.settings.editable.field.action.cancel": "Annuler",
"account.settings.editable.field.action.edit": "Modifier",
"account.settings.static.field.empty": "Aucune valeur n'a été fixée. Contactez l'administrateur de votre {entreprise} pour effectuer des modifications.",
"account.settings.static.field.empty.no.admin": "Pas de valeur définie.",
"account.settings.field.name.certificate.select": "Si sélectionné, ce nom va apparaître sur vos attestations et dossiers publics.",
"account.settings.field.name.modal.certificate.title": "Choisissez le nom qui va apparaîtres sur vos attestations et dossiers publics.",
"account.settings.field.name.modal.certificate.select": "Sélectionnez un nom",
"account.settings.field.name.modal.certificate.option.full": "Nom complet",
"account.settings.field.name.modal.certificate.option.verified": "Nom vérifié",
"account.settings.field.name.modal.certificate.button.choose": "Choisissez un nom",
"account.settings.coaching.consent.welcome.header": "Commençons.",
"account.settings.coaching.consent.welcome.subheader": "Nous sommes là pour vous du début à la fin",
"account.settings.coaching.consent.description": "Les programmes MicroBachelors comprennent un coaching axé sur votre carrière, vos études et la façon dont vous obtiendrez des résultats grâce à une communication individuelle avec un professionnel expérimenté. Si vous êtes intéressé, fournissez les informations ci-dessous et cliquez sur \"Soumettre\". Notre partenaire de coaching vous contactera par courrier électronique et/ou par SMS pour vous aider à progresser. Les conditions générales s'appliquent.*",
"account.settings.coaching.consent.text-messaging.disclaimer": "* Les services de coaching sont inclus sans frais supplémentaires pour les apprenants ayant un numéro de téléphone aux États-Unis. Le coaching comprend des messages textes récurrents. Les tarifs des messages et des données peuvent s'appliquer. Text STOP pour se désengager.",
"account.settings.coaching.consent.accept-coaching": "S'inscrire pour le coaching.",
"account.settings.coaching.consent.decline-coaching": "Je préfère ne pas être contacté par les services de coaching gratuit.",
"account.settings.coaching.consent.label.name": "Veuillez confirmer votre nom",
"account.settings.coaching.consent.label.phone-number": "Entrer un numéro de cellulaire",
"account.settings.coaching.consent.success.header": "Opération réussie!",
"account.settings.coaching.consent.success.message": "Vous êtes inscrit au coaching. Vous pouvez vous attendre à un message par courriel ou SMS dans les prochains jours.",
"account.settings.coaching.consent.success.continue": "Démarrer mon cours",
"account.settings.coaching.managed.support": "support",
"account.settings.coaching.managed.alert": "Votre nom est géré par {managerTitle}. Contactez votre administrateur pour obtenir de l'aide.",
"account.settings.field.phone_number": "Numéro de téléphone",
"account.settings.field.phone_number.empty": "Ajouter un numéro de téléphone",
"account.settings.field.coaching_consent": "Consentement pour le coaching",
"account.settings.field.coaching_consent.tooltip": "Un parcours MicroBachelors inclus du coaching par texto avec un professionnel expériementé qui vous aidera à combiner votre expérience éducationnelle et vos objectifs de carrière. Les services de coaching sont inclus sans coût additionnel aux apprenant ayant un numéro de téléphone US. Le coût standard des textos s'applique. Texter 'STOP' en tout temp pour arrêter les messages.",
"account.settings.field.coaching_consent.error": "Un numéro de téléphone US valide est requis pour s'inscrire pour du coaching",
"account.settings.delete.account.before.proceeding": "Avant de poursuivre, veuillez {actionLink}.",
"account.settings.delete.account.header": "Supprimer mon compte",
"account.settings.delete.account.subheader": "Nous sommes désolés de vous voir quitter!",
"account.settings.delete.account.text.1": "Veuillez noter que la suppression de votre compte et de vos données personnelles est permanente et ne peut être annulée. {siteName} ne pourra pas récupérer votre compte ou les données supprimées.",
"account.settings.delete.account.text.2": "Une fois votre compte supprimé, vous ne pourrez plus l'utiliser pour suivre des cours sur {siteName}.",
"account.settings.delete.account.text.2.edX": "Une fois votre compte supprimé, vous ne pourrez plus l'utiliser pour prendre des cours sur l'application edX, edx.org, ou tout autre site hébergé par edX. Cela comprend l'accès à edx.org à partir du système de votre employeur ou de votre université et l'accès aux sites privés offerts par MIT Open Learning, Wharton Executive Education, et Harvard Medical School.",
"account.settings.delete.account.text.3.link": "Suivez ces instructions pour imprimer ou télécharger une attestation",
"account.settings.delete.account.text.warning": "Avertissement : la suppression d'un compte est permanente. Veuillez lire attentivement ce qui précède avant de continuer. Cette action est irréversible et vous ne pourrez plus utiliser la même adresse courriel sur {siteName}.",
"account.settings.delete.account.text.change.instead": "Vous souhaitez modifier votre adresse électronique, votre nom ou votre mot de passe?",
"account.settings.delete.account.button": "Supprimer mon compte",
"account.settings.delete.account.please.activate": "activez votre compte",
"account.settings.delete.account.please.confirm": "confirmer votre compte",
"account.settings.delete.account.please.unlink": "dissocier tous les comptes de médias sociaux",
"account.settings.delete.account.modal.header": "Êtes-vous certain ?",
"account.settings.delete.account.modal.text.1": "Vous avez sélectionné \"Supprimer mon compte\". La suppression de votre compte et de vos données personnelles est permanente et ne peut être annulée. {siteName} ne pourra ni récupérer votre compte ni les données supprimées.",
"account.settings.delete.account.modal.text.2": "Si vous continuez, vous ne pourrez plus utiliser ce compte pour suivre des cours sur {siteName}.",
"account.settings.delete.account.modal.text.2.edX": "Si vous procédez ainsi, vous ne pourrez pas utiliser ce compte pour suivre des cours sur l'application edX, edx.org ou tout autre site hébergé par edX. Cela inclut l'accès à edx.org depuis le système de votre employeur ou de votre université et l'accès aux sites privés proposés par MIT Open Learning, Wharton Executive Education et Harvard Medical School.",
"account.settings.delete.account.modal.enter.password": "Si vous souhaitez toujours supprimer votre compte, veuillez saisir le mot de passe de votre compte :",
"account.settings.delete.account.modal.confirm.delete": "Oui, supprimer",
"account.settings.delete.account.modal.confirm.cancel": "Annuler",
"account.settings.delete.account.error.unable.to.delete": "Impossible de supprimer le compte",
"account.settings.delete.account.error.no.password": "Un mot de passe est requis",
"account.settings.delete.account.error.invalid.password": "Mot de passe incorrect.",
"account.settings.delete.account.error.unable.to.delete.details": "Nous sommes désolés, il y a eu une erreur dans le suivi de votre demande. Veuillez réessayer plus tard.",
"account.settings.delete.account.modal.after.header": "Nous sommes désolés de vous voir quitter! Votre compte sera bientôt supprimé.",
"account.settings.delete.account.modal.after.text": "La suppression d'un compte, comprenant le retrait des listes d'e-mail, peu prendre quelques semaines afin de traiter entièrement notre système. Si vous souhaitez renoncer aux e-mails ultérieurement, veuillez vous désinscrire en consultant le pied de page de n'importe quel e-mail.",
"account.settings.delete.account.modal.after.button": "Fermer",
"account.settings.delete.account.text.3.edX": "Vous pouvez également perdre l'accès aux attestations vérifiées et à d'autres informations d'identification de programme, comme les attestations MicroMasters. Vous pouvez en faire une copie pour vos dossiers avant de procéder à la suppression. {actionLink}.",
"account.settings.delete.account.text.3": "Vous pouvez également perdre accès aux attestations vérifiées et à d'autres informations d'identification de programme. Vous pouvez en faire une copie pour vos dossiers avant de procéder à la suppression.",
"account.settings.message.demographics.service.issue": "Une erreur s'est produite lors de la tentative de récupération ou d'enregistrement des informations de votre compte. Veuillez réessayer plus tard.",
"account.settings.field.demographics.gender": "Identité de genre",
"account.settings.field.demographics.gender.empty": "Ajouter une identité de genre",
"account.settings.field.demographics.gender.options.empty": "Sélectionnez une identité de genre",
"account.settings.field.demographics.gender_description": "Description de l'identité de genre",
"account.settings.field.demographics.gender_description.empty": "Entrez la description",
"account.settings.field.demographics.ethnicity": "Identité raciale / ethnique",
"account.settings.field.demographics.ethnicity.empty": "Ajouter une identité raciale / ethnique",
"account.settings.field.demographics.ethnicity.options.empty": "Sélectionnez tout ce qui s'y rapporte",
"account.settings.field.demographics.income": "Revenu familial",
"account.settings.field.demographics.income.empty": "Ajouter le revenu familial",
"account.settings.field.demographics.income.options.empty": "Sélectionnez une fourchette de revenu familial",
"account.settings.field.demographics.military_history": "Statut militaire U.S.",
"account.settings.field.demographics.military_history.empty": "Ajouter un statut militaire",
"account.settings.field.demographics.military_history.options.empty": "Sélectionnez un statut militaire",
"account.settings.field.demographics.learner_education_level": "Votre niveau d'éducation",
"account.settings.field.demographics.learner_education_level.empty": "Ajouter un niveau d'éducation",
"account.settings.field.demographics.parent_education_level": "Niveau d'éducation des parents / tuteurs",
"account.settings.field.demographics.parent_education_level.empty": "Ajouter un niveau d'éducation",
"account.settings.field.demographics.education_level.options.empty": "Sélectionnez le niveau d'éducation",
"account.settings.field.demographics.work_status": "Statut d'emploi",
"account.settings.field.demographics.work_status.empty": "Ajouter un statut d'emploi",
"account.settings.field.demographics.work_status.options.empty": "Sélectionnez le statut d'emploi",
"account.settings.field.demographics.work_status_description": "Description du statut d'emploi",
"account.settings.field.demographics.work_status_description.empty": "Entrez la description",
"account.settings.field.demographics.current_work_sector": "Secteur d'emploi actuel",
"account.settings.field.demographics.current_work_sector.empty": "Ajouter le secteur d'emploi",
"account.settings.field.demographics.future_work_sector": "Secteur d'emploi futur",
"account.settings.field.demographics.future_work_sector.empty": "Ajouter le secteur d'emploi",
"account.settings.field.demographics.work_sector.options.empty": "Sélectionnez un secteur d'emploi",
"account.settings.section.demographics.why": "Pourquoi est-ce que {siteName} collecte ces informations ?",
"account.settings.name.change.title.id": "Ce changement de nom requiert une vérification d'identité.",
"account.settings.name.change.title.begin": "Avant que l'on commençons",
"account.settings.name.change.warning.one": "Warning: This action updates the name that appears on all certificates that have been earned on this account in the past and any certificates you are currently earning or will earn in the future.",
"account.settings.name.change.warning.two": "Cette action ne peut pas être renversée sans vérification d'identité.",
"account.settings.name.change.id.name.label": "Entrez votre nom tel qu&#39;il apparaît sur votre carte d&#39;étudiant, de travail ou d&#39;identité émise par le gouvernement.",
"account.settings.name.change.id.name.placeholder": "Entrez le nom sur votre pièce d&#39;identité avec photo",
"account.settings.name.change.error.valid.name": "Entrez un nom valide",
"account.settings.name.change.error.general": "Une erreur est survenue. Veuillez réessayer.",
"account.settings.name.change.continue": "Continuer",
"account.settings.name.change.cancel": "Annuler",
"error.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.",
"account.settings.editable.field.password.reset.button.confirmation.support.link": "technical support",
"account.settings.editable.field.password.reset.button.confirmation": "Nous avons envoyé un message à {email}. Cliquez sur le lien dans le message pour réinitialiser votre mot de passe. Vous n'avez pas reçu le message? Contactez {technicalSupportLink}.",
"account.settings.editable.field.password.reset.button": "Réinitialiser le mot de passe",
"account.settings.editable.field.password.reset.button.forbidden": "Votre demande précédente est en cours, veuillez réessayer dans quelques instants.",
"account.settings.editable.field.password.reset.label": "Mot de passe",
"account.settings.sso.link.account": "Se connecter avec {name}",
"account.settings.sso.account.connected": "Lié",
"account.settings.sso.account.disconnect.error": "Un problème est survenu lors de la déconnexion de ce compte. Contactez le support si le problème persiste.",
"account.settings.sso.unlink.account": "Dissocier le compte {name}",
"account.settings.sso.no.providers": "Aucun compte ne peut être lié pour le moment.",
"account.page.title": "Account | {siteName}",
"id.verification.access.blocked.denied": "Nous ne pouvez pas vérifier votre identité pour le moment. Si vous n'avez pas encore activé votre compte, veuillez vérifier votre dossier de pourriels pour le courriel d'activation de {email}.",
"id.verification.next": "Suivant",
"id.verification.support": "support",
"id.verification.example.card.alt": "Exemple de carte d'identité valide avec un nom complet et une photo.",
"id.verification.requirements.title": "Exigences de vérification des photos",
"id.verification.requirements.description": "Afin de procéder à la vérification des photos, vous aurez besoin des éléments suivants :",
"id.verification.requirements.card.device.title": "Appareil avec caméra",
"id.verification.requirements.card.device.allow": "Autoriser",
"id.verification.requirements.card.id.title": "Carte d'identité avec photo",
"id.verification.requirements.card.id.text": "Vous avez besoin d'une carte d'identité valide contenant votre nom complet et votre photo, comme un permis de conduire ou un passeport.",
"id.verification.privacy.title": "Information sur la confidentialité",
"id.verification.privacy.need.photo.question": "Pourquoi est-ce que {siteName} a besoin de ma photo?",
"id.verification.privacy.need.photo.answer": "Nous utilisons vos photos de vérification pour confirmer votre identité et assurer la validité de votre certificat.",
"id.verification.privacy.do.with.photo.question": "Qu'est-ce que {siteName} fait avec cette photo?",
"id.verification.privacy.do.with.photo.answer": "Nous chiffrons votre photo de manière sécurisée et l'envoyons à notre service d'autorisation pour vérification. Votre photo et vos informations ne sont pas enregistrées ni visibles nulle part sur {siteName} une fois le processus de vérification terminé.",
"id.verification.access.blocked.title": "Vérification d'identité",
"id.verification.access.blocked.enrollment": "Vous n'êtes actuellement pas inscrit à un cours nécessitant une vérification d'identité.",
"id.verification.access.blocked.pending": "Vous avez déjà soumis vos informations de vérification. Vous verrez un message sur votre tableau de bord lorsque le processus de vérification sera terminé (généralement dans les 5 jours).",
"id.verification.photo.take": "Prendre une photo",
"id.verification.photo.retake": "Reprendre la photo ?",
"id.verification.photo.enable.detection": "Activer la détection des visages",
"id.verification.photo.enable.detection.portrait.help.text": "Si coché, une case apparaîtra autour de votre visage. Votre visage peut être vu clairement si la boîte qui l'entoure est bleue. Si votre visage n'est pas dans une bonne position ou indétectable, la case sera rouge.",
"id.verification.photo.enable.detection.id.help.text": "Si coché, une case apparaîtra autour du visage sur votre pièce d'identité. Le visage peut être vu clairement si la boîte qui l'entoure est bleue. Si le visage n'est pas dans une bonne position ou indétectable, la case sera rouge.",
"id.verification.photo.feedback.correct": "Le visage est en bonne position.",
"id.verification.photo.feedback.two.faces": "Plus d'un visage détecté.",
"id.verification.photo.feedback.no.faces": "Aucun visage détecté.",
"id.verification.photo.feedback.top.left": "Position incorrecte. En haut à gauche.",
"id.verification.photo.feedback.top.center": "Position incorrecte. En haut au centre.",
"id.verification.photo.feedback.top.right": "Position incorrecte. En haut à droite.",
"id.verification.photo.feedback.center.left": "Position incorrecte. Centre gauche.",
"id.verification.photo.feedback.center.center": "Position incorrecte. Trop près de la caméra.",
"id.verification.photo.feedback.center.right": "Position incorrecte. Centre droit.",
"id.verification.photo.feedback.bottom.left": "Position incorrecte. En bas à gauche.",
"id.verification.photo.feedback.bottom.center": "Position incorrecte. En bas au centre.",
"id.verification.photo.feedback.bottom.right": "Position incorrecte. En bas à droite.",
"id.verification.camera.access.title": "Autorisations de la caméra",
"id.verification.camera.access.title.success": "Accès à la caméra activé",
"id.verification.camera.access.title.failed": "L'accès à la caméra a échoué",
"id.verification.camera.access.click.allow": "Veuillez vous assurer de cliquer sur \"Autoriser\"",
"id.verification.camera.access.enable": "Activer la caméra",
"id.verification.camera.access.problems": "Vous avez des problèmes?",
"id.verification.camera.access.skip": "Ignorer et télécharger les fichiers image au lieu",
"id.verification.camera.access.success": "Il semble que votre appareil photo fonctionne et est prêt.",
"id.verification.camera.access.failure": "Il semble que nous ne puissions pas accéder à votre caméra. Vous devrez télécharger des fichiers image de vous et de votre pièce d'identité.",
"id.verification.camera.access.failure.temporary": "Il semblerait que nous ne pouvons pas accéder à votre caméra. Vérifiez qu'elle est bien connectée et que votre navigateur est autorisé à y accéder.",
"id.verification.camera.access.failure.temporary.chrome": "Pour activer l'accès à la caméra dans Chrome:",
"id.verification.camera.access.failure.temporary.chrome.step1": "Ouvrir Chrome.",
"id.verification.camera.access.failure.temporary.chrome.step2": "Accédez à Plus> Paramètres.",
"id.verification.camera.access.failure.temporary.chrome.step2.windows": "Pour Windows: Alt+F, Alt+E ou F10 suivi de la barre d'espace",
"id.verification.camera.access.failure.temporary.chrome.step2.mac": "Pour Mac: Command+,",
"id.verification.camera.access.failure.temporary.chrome.step3": "Sous l'onglet «Confidentialité et sécurité», sélectionnez «Paramètres du site», puis «Appareil photo».",
"id.verification.camera.access.failure.temporary.chrome.step4": "Sous \"Bloqué\", trouvez \"edx.org\" et sélectionnez-le.",
"id.verification.camera.access.failure.temporary.chrome.step5": "Dans la section \"Autorisations\", mettez à jour les autorisations de la caméra pour \"Autoriser\".",
"id.verification.camera.access.failure.temporary.ie11": "Pour activer l'accès à la caméra dans Internet Explorer:",
"id.verification.camera.access.failure.temporary.ie11.step1": "Ouvrez le Gestionnaire des paramètres de Flash Player en accédant à Paramètres Windows> Panneau de configuration> Flash Player.",
"id.verification.camera.access.failure.temporary.ie11.step2": "Sélectionnez l'onglet \"Caméra et micro\", puis sélectionnez le bouton \"Paramètres de la caméra et du microphone par site\".",
"id.verification.camera.access.failure.temporary.ie11.step3": "Choisissez \"edx.org\" dans la liste des sites Web et modifiez les autorisations en sélectionnant \"Autoriser\" dans le menu déroulant.",
"id.verification.camera.access.failure.temporary.firefox": "Pour activer l'accès à la caméra dans Firefox:",
"id.verification.camera.access.failure.temporary.firefox.step1": "Ouvrez Firefox.",
"id.verification.camera.access.failure.temporary.firefox.step2": "Saisissez \"about:preferences\" dans la barre d'URL.",
"id.verification.camera.access.failure.temporary.firefox.step3": "Sélectionnez l'onglet \"Confidentialité et sécurité\" et accédez à la section \"Autorisations\".",
"id.verification.camera.access.failure.temporary.firefox.step4": "À côté de \"Appareil photo\", sélectionnez le bouton \"Paramètres…\".",
"id.verification.camera.access.failure.temporary.firefox.step5": "Dans la barre de recherche, entrez \"edx.org\".",
"id.verification.camera.access.failure.temporary.firefox.step6": "Dans la colonne d'état de \"edx.org\", sélectionnez \"Autoriser\" dans la liste déroulante.",
"id.verification.camera.access.failure.temporary.firefox.step7": "Sélectionnez \"Enregistrer les modifications\".",
"id.verification.camera.access.failure.temporary.safari": "Pour activer l'accès à la caméra dans Safari:",
"id.verification.camera.access.failure.temporary.safari.step1": "Ouvrir Safari.",
"id.verification.camera.access.failure.temporary.safari.step2": "Cliquez sur le menu de l'application Safari, puis sélectionnez \"Préférences\". Vous pouvez également utiliser Command+ comme raccourci clavier.",
"id.verification.camera.access.failure.temporary.safari.step3": "Sélectionnez l'onglet \"Sites Web\", puis sélectionnez \"Appareil photo\".",
"id.verification.camera.access.failure.temporary.safari.step4": "Sélectionnez \"edx.org\" et changez les autorisations de la caméra en \"Allow\".",
"id.verification.camera.access.failure.unsupported": "Il semble que votre fureteur ne prend pas en charge l'accès à la caméra.",
"id.verification.camera.access.failure.unsupported.chrome.explanation": "Le fureteur Chrome ne prend actuellement pas en charge l'accès à la caméra sur les appareils iOS, tels que les iPhones et les iPad.",
"id.verification.camera.access.failure.unsupported.instructions": "Veuillez utiliser un autre navigateur pour terminer la vérification d'identité.",
"id.verification.photo.tips.title": "Conseils photo utiles",
"id.verification.photo.tips.description": "Ensuite, nous aurons besoin de vous preniez une photo de votre visage. Veuillez consulter les conseils utiles ci-dessous.",
"id.verification.photo.tips.list.title": "Conseils photo",
"id.verification.photo.tips.list.description": "Pour prendre une bonne photo, assurez-vous que: ",
"id.verification.photo.tips.list.well.lit": "Votre visage est bien éclairé",
"id.verification.photo.tips.list.inside.frame": " Votre visage est entièrement dans le cadre.",
"id.verification.portrait.photo.title.camera": "Prenez une photo de vous",
"id.verification.portrait.photo.instructions.camera": "Lorsque votre visage est en position, utilisez le bouton Prendre une photo ci-dessous pour prendre votre photo.",
"id.verification.camera.help.sight.question": "Que faire si je ne peux pas voir l'image de la caméra ou si je ne peux pas voir ma photo pour déterminer quel côté est visible?",
"id.verification.camera.help.sight.answer.portrait": "Vous pourrez peut-être terminer la procédure de capture d'image sans aide, mais cela peut prendre quelques tentatives de soumission pour obtenir le bon positionnement de la caméra. Le positionnement optimal de la caméra varie avec chaque ordinateur, mais généralement la meilleure position pour une prise de vue de la tête est d'environ 12-18 pouces (30-45 centimètres) de la caméra, la tête étant centrée par rapport à l'écran de l'ordinateur. Si les photos que vous soumettez sont rejetées, essayez de déplacer lorientation de lordinateur ou de lappareil photo pour modifier langle déclairage.",
"id.verification.camera.help.sight.answer.id": "Vous pourrez peut-être terminer la procédure de capture d'image sans aide, mais cela peut prendre quelques tentatives de soumission pour obtenir le bon positionnement de la caméra. Le positionnement optimal de la caméra varie avec chaque ordinateur, mais généralement, la meilleure position pour une photo d'une carte d'identité est de 8-12 pouces (20-30 centimètres) de la caméra, la carte d'identité étant centrée par rapport à la caméra. Si les photos que vous soumettez sont rejetées, essayez de déplacer lorientation de lordinateur ou de lappareil photo pour modifier langle déclairage. La raison la plus courante de rejet est l'incapacité de lire le texte sur la carte d'identité.",
"id.verification.camera.help.difficulty.question.portrait": "Que faire si j'ai des difficultés à maintenir ma tête en position par rapport à la caméra ?",
"id.verification.camera.help.difficulty.question.id": "Que faire si j'ai des difficultés à tenir ma carte d'identité en position par rapport à la caméra ?",
"id.verification.camera.help.difficulty.answer": "Si vous avez besoin d'aide pour prendre une photo à soumettre, contactez le support {siteName} pour des suggestions supplémentaires.",
"id.verification.id.photo.unclear.question": "L'image de votre carte d'identité n'est pas claire ou trop floue ?",
"id.verification.id.tips.title": "Conseils utiles pour les cartes d'identité",
"id.verification.id.tips.description": "Ensuite, nous vous demanderons de prendre une photo d'une carte d'identité valide comportant votre nom complet et votre photo, comme un permis de conduire ou un passeport. Veuillez préparer votre carte d'identité.",
"id.verification.id.tips.list.well.lit": "Votre carte d'identité est bien éclairée.",
"id.verification.id.tips.list.clear": "Assurez-vous que vous pouvez voir votre photo et lire clairement votre nom.",
"id.verification.id.photo.title.camera": "Prenez une photo de votre carte d'identité",
"id.verification.id.photo.title.upload": "Téléversez une photo de votre carte d'identité",
"id.verification.id.photo.preview.alt": "Aperçu de la pièce d'identité avec photo.",
"id.verification.id.photo.instructions.camera": "Lorsque votre pièce d'identité est en place, utilisez le bouton Prendre une photo ci-dessous pour prendre votre photo. Veuillez utiliser un passeport, un permis de conduire ou une autre carte d'identité comportant votre nom complet et une photo de votre visage.",
"id.verification.id.photo.instructions.upload": "Veuillez téléverser une photo de votre carte d'identité. Assurez-vous que la totalité de la carte d'identité rentre dans le cadre et qu'elle est bien éclairée. La taille du fichier doit être inférieure à 10 Mo. Formats pris en charge : ",
"id.verification.id.photo.instructions.upload.error.invalidFileType": "Le fichier que vous avez sélectionné n'est pas un type d'image pris en charge. Veuillez choisir parmi les formats suivants :",
"id.verification.id.photo.instructions.upload.error.fileTooLarge": "Le fichier que vous avez sélectionné est trop volumineux. Veuillez réessayer avec un fichier de moins de 10 Mo.",
"id.verification.name.check.title": "Vérifiez votre nom",
"id.verification.name.check.instructions": "Le nom ci-dessous correspond-il au nom sur votre pièce d&#39;identité avec photo ? Si ce n&#39;est pas le cas, mettez à jour le nom ci-dessous pour qu&#39;il corresponde à votre pièce d&#39;identité avec photo.",
"id.verification.name.check.mismatch.information": "Si le nom ci-dessous ne correspond pas à votre pièce d&#39;identité avec photo, votre vérification d&#39;identité sera refusée.",
"id.verification.name.error": "Veuillez entrer votre nom tel qu&#39;il apparaît sur votre pièce d&#39;identité avec photo.",
"id.verification.account.name.warning.prefix": "Veuillez noter:",
"id.verification.account.name.settings": "Paramètres du compte",
"id.verification.name.label": "Nom",
"id.verification.account.name.photo.alt": "Photo de votre pièce d'identité à soumettre.",
"id.verification.review.title": "Vérifiez vos photos",
"id.verification.review.description": "Assurez-vous que nous pourrons vérifier votre identité avec les photos et les informations fournies.",
"id.verification.review.portrait.label": "Votre portrait",
"id.verification.review.portrait.alt": "Photo de votre visage à soumettre.",
"id.verification.review.portrait.retake": "Reprendre la photo de portrait",
"id.verification.review.id.label": "Votre carte d'identité",
"id.verification.review.id.alt": "Photo de votre carte d'identité à présenter.",
"id.verification.review.id.retake": "Reprendre la photo de la pièce d'identité",
"id.verification.review.confirm": "Envoyez",
"id.verification.submission.alert.error.face": "Une photo de votre visage est requise. Veuillez reprendre votre photo de portrait.",
"id.verification.submission.alert.error.id": "Une photo de votre pièce d'identité est requise. Veuillez reprendre votre photo d'identité.",
"id.verification.submission.alert.error.name": "Un nom de compte valide est requis. Veuillez mettre à jour le nom de votre compte pour qu'il corresponde au nom sur votre pièce d'identité.",
"id.verification.submission.alert.error.unsupported": "Un ou plusieurs des fichiers que vous avez téléchargés sont dans un format non pris en charge. Veuillez choisir parmi les formats suivants :",
"id.verification.review.error": "Page de Support {siteName}",
"id.verification.submitted.title": "Vérification d'identité en cours",
"id.verification.submitted.text": "Nous avons reçu vos informations et vérifions votre identité. Vous serez averti lorsque le processus de vérification sera terminé (généralement dans les 5 jours). En attendant, vous pouvez toujours accéder à tous les contenus de cours disponibles.",
"id.verification.return.dashboard": "Retour au Tableau de bord",
"id.verification.return.course": "Revenir au cours",
"id.verification.return.generic": "Retour",
"id.verification.photo.upload.help.title": "Téléchargez une photo à la place",
"id.verification.photo.camera.help.title": "Utilisez votre appareil photo à la place",
"id.verification.photo.upload.help.text": "Si vous rencontrez des difficultés lors de l'utilisation de la capture de photo ci-dessus, vous souhaiterez peut-être télécharger une photo à la place. Pour télécharger une photo, cliquez sur le bouton ci-dessous.",
"id.verification.photo.camera.help.text": "Si vous rencontrez des difficultés pour télécharger une photo ci-dessus, vous pouvez utiliser votre appareil photo à la place. Pour utiliser votre appareil photo, cliquez sur le bouton ci-dessous.",
"id.verification.upload.help.button": "Passer en mode de téléchargement",
"id.verification.camera.help.button": "Passer en mode caméra",
"id.verification.request.camera.access.instructions": "Afin de prendre une photo à l'aide de votre webcam, vous pouvez recevoir une invite du navigateur pour accéder à votre caméra. {clickAllow}",
"id.verification.requirements.account.managed.alert": "Les paramètres de votre compte sont gérés par {managerTitle}. Si le nom sur votre pièce d'identité avec photo ne correspond pas au nom de votre compte, veuillez contacter votre administrateur {profileDataManager} ou {support} pour obtenir de l'aide avant de terminer le processus de vérification des photos.",
"id.verification.requirements.card.device.text": "Vous avez besoin d'un appareil équipé d'une caméra. Si vous recevez une invite du navigateur pour accéder à votre caméra, assurez-vous de cliquer sur {allow}.",
"id.verification.account.name.summary.alert": "Les paramètres de votre compte sont gérés par {managerTitle}. Si le nom sur votre pièce d'identité avec photo ne correspond pas au nom de votre compte, veuillez contacter votre administrateur {profileDataManager} ou {support} pour obtenir de l'aide.",
"idv.submission.alert.error": "\n Nous avons rencontré une erreur technique en essayant de soumettre la vérification d'identité.\n Il peut s'agir d'un problème temporaire. Veuillez réessayer dans quelques minutes.\n Si le problème persiste, veuillez consulter {support_link} pour obtenir de l'aide.\n ",
"id.verification.account.name.edit": "Modifier {sr}"
}

View File

@@ -1,11 +0,0 @@
{
"siteheader.links.courses": "Courses",
"siteheader.links.programs": "Programs & Degrees",
"siteheader.links.schools": "Schools & Partners",
"siteheader.user.menu.dashboard": "Dashboard",
"siteheader.user.menu.profile": "Profile",
"siteheader.user.menu.account.settings": "Account",
"siteheader.user.menu.logout": "Logout",
"siteheader.user.menu.login": "Login",
"siteheader.user.menu.register": "Sign Up"
}

View File

@@ -1,11 +0,0 @@
{
"siteheader.links.courses": "Courses",
"siteheader.links.programs": "Programs & Degrees",
"siteheader.links.schools": "Schools & Partners",
"siteheader.user.menu.dashboard": "Dashboard",
"siteheader.user.menu.profile": "Profile",
"siteheader.user.menu.account.settings": "Account",
"siteheader.user.menu.logout": "Logout",
"siteheader.user.menu.login": "Login",
"siteheader.user.menu.register": "Sign Up"
}

View File

@@ -1,11 +0,0 @@
{
"siteheader.links.courses": "Courses",
"siteheader.links.programs": "Programs & Degrees",
"siteheader.links.schools": "Schools & Partners",
"siteheader.user.menu.dashboard": "Dashboard",
"siteheader.user.menu.profile": "Profile",
"siteheader.user.menu.account.settings": "Account",
"siteheader.user.menu.logout": "Logout",
"siteheader.user.menu.login": "Login",
"siteheader.user.menu.register": "Sign Up"
}

View File

@@ -1,11 +0,0 @@
{
"siteheader.links.courses": "Courses",
"siteheader.links.programs": "Programs & Degrees",
"siteheader.links.schools": "Schools & Partners",
"siteheader.user.menu.dashboard": "Dashboard",
"siteheader.user.menu.profile": "Profile",
"siteheader.user.menu.account.settings": "Account",
"siteheader.user.menu.logout": "Logout",
"siteheader.user.menu.login": "Login",
"siteheader.user.menu.register": "Sign Up"
}

View File

@@ -1,11 +0,0 @@
{
"siteheader.links.courses": "Courses",
"siteheader.links.programs": "Programs & Degrees",
"siteheader.links.schools": "Schools & Partners",
"siteheader.user.menu.dashboard": "Dashboard",
"siteheader.user.menu.profile": "Profile",
"siteheader.user.menu.account.settings": "Account",
"siteheader.user.menu.logout": "Logout",
"siteheader.user.menu.login": "Login",
"siteheader.user.menu.register": "Sign Up"
}

View File

@@ -1,11 +0,0 @@
{
"siteheader.links.courses": "Courses",
"siteheader.links.programs": "Programs & Degrees",
"siteheader.links.schools": "Schools & Partners",
"siteheader.user.menu.dashboard": "Dashboard",
"siteheader.user.menu.profile": "Profile",
"siteheader.user.menu.account.settings": "Account",
"siteheader.user.menu.logout": "Logout",
"siteheader.user.menu.login": "Login",
"siteheader.user.menu.register": "Sign Up"
}

View File

@@ -1,11 +0,0 @@
{
"siteheader.links.courses": "Courses",
"siteheader.links.programs": "Programs & Degrees",
"siteheader.links.schools": "Schools & Partners",
"siteheader.user.menu.dashboard": "Dashboard",
"siteheader.user.menu.profile": "Profile",
"siteheader.user.menu.account.settings": "Account",
"siteheader.user.menu.logout": "Logout",
"siteheader.user.menu.login": "Login",
"siteheader.user.menu.register": "Sign Up"
}

View File

@@ -1,11 +0,0 @@
{
"siteheader.links.courses": "Courses",
"siteheader.links.programs": "Programs & Degrees",
"siteheader.links.schools": "Schools & Partners",
"siteheader.user.menu.dashboard": "Dashboard",
"siteheader.user.menu.profile": "Profile",
"siteheader.user.menu.account.settings": "Account",
"siteheader.user.menu.logout": "Logout",
"siteheader.user.menu.login": "Login",
"siteheader.user.menu.register": "Sign Up"
}

View File

@@ -1,359 +0,0 @@
{
"account.settings.message.duplicate.tpa.provider": "The {provider} account you selected is already linked to another {siteName} account.",
"account.settings.message.managed.settings": "Your profile settings are managed by {managerTitle}. Contact your administrator or {support} for help.",
"account.settings.message.managed.settings.support": "support",
"account.settings.page.heading": "Account Settings",
"account.settings.loading.message": "Loading...",
"account.settings.loading.error": "Error: {error}",
"account.settings.banner.beta.language": "You have set your language to {beta_language}, which is currently not fully translated. You can help us translate this language fully by joining the Transifex community and adding translations from English for learners that speak {beta_language}.",
"account.settings.banner.beta.language.action.switch.back": "Switch Back to {previous_language}",
"account.settings.banner.beta.language.action.help.translate": "Help Translate into {beta_language}",
"account.settings.section.account.information": "Account Information",
"account.settings.section.account.information.description": "These settings include basic information about your account.",
"account.settings.section.profile.information": "Profile Information",
"account.settings.section.demographics.information": "Optional Information",
"account.settings.section.site.preferences": "Site Preferences",
"account.settings.section.linked.accounts": "Linked Accounts",
"account.settings.section.linked.accounts.description": "You can link your identity accounts to simplify signing in to {siteName}.",
"account.settings.field.username": "Username",
"account.settings.field.username.help.text": "The name that identifies you on {siteName}. You cannot change your username.",
"account.settings.field.full.name": "Full name",
"account.settings.field.full.name.empty": "Add name",
"account.settings.field.full.name.help.text": "The name that is used for ID verification and that appears on your certificates.",
"account.settings.field.full.name.help.text.default": "The name that appears on your public profile.",
"account.settings.field.full.name.help.text.default.certificate": "This name is selected to appear on your certificates and public-facing records.",
"account.settings.field.name.verified": "Verified name",
"account.settings.field.name.verified.help.text.verified": "This name has been verified by photo ID.",
"account.settings.field.name.verified.help.text.verified.proctored": "This name has been verified by proctoring.",
"account.settings.field.name.verified.help.text.verified.certificate": "This name has been verified by photo ID, and is selected to appear on your certificates and public-facing records.",
"account.settings.field.name.verified.help.text.verified.proctored.certificate": "This name has been verified by proctoring, and is selected to appear on your certificates and public-facing records.",
"account.settings.field.name.verified.help.text.submitted": "Verification has been submitted. This usually takes 48 hours or less. Verified name cannot be changed at this time.",
"account.settings.field.name.verified.help.text.submitted.proctored": "Your proctored exam has been submitted. Verified name cannot be changed at this time. Please check back in 2-5 days.",
"account.settings.field.name.verified.help.text.submitted.certificate": "When identity verification is successful, this name will appear on your certificates and public-facing records. Verified name cannot be changed at this time.",
"account.settings.field.name.verified.help.text.submitted.proctored.certificate": "Once your proctored exam passes review, this name will appear on your certificate and public-facing records. Verified Name cannot be changed at this time.",
"account.settings.field.name.verified.verification.help": "Enter your name as it appears on your unexpired student, work, or government-issued identification card.",
"account.settings.field.full.name.help.text.submitted": "Verification has been submitted. This usually takes 48 hours or less. Full name cannot be changed at this time.",
"account.settings.field.full.name.help.text.submitted.proctored": "Your proctored exam has been submitted. Full name cannot be changed at this time. Please check back in 2-5 days.",
"account.settings.field.full.name.help.text.submitted.certificate": "When identity verification is successful, this name will appear on your certificates and public-facing records. Full name cannot be changed at this time.",
"account.settings.field.full.name.help.text.submitted.proctored.certificate": "Once your proctored exam passes review, this name will appear on your certificates and public-facing records. Full name cannot be changed at this time.",
"account.settings.field.name.verified.success.message": "Your identity verification request has successfully completed. You now have the option of selecting which name you prefer to appear on your certificates and public-records.",
"account.settings.field.name.verified.success.message.header": "Your name change request is complete!",
"account.settings.field.name.verified.failure.message": "Your most recent identity verification attempt did not pass. Related account settings have been restored.",
"account.settings.field.name.verified.failure.message.header": "We were not able to verify your identity.",
"account.settings.field.name.verified.failure.message.help.link": "Learn more about ID verification",
"account.settings.field.name.verified.submitted.message": "Your identity verification request has been submitted and usually takes between 24 and 48 hours to complete.",
"account.settings.field.name.verified.submitted.message.certificate": "When your request is approved, your updated name will appear on all associated certificates and public-facing records.",
"account.settings.field.name.verified.submitted.message.header": "Your name change request is almost complete!",
"account.settings.field.email": "Email address (Sign in)",
"account.settings.field.email.empty": "Add email address",
"account.settings.field.email.confirmation": "Weve sent a confirmation message to {value}. Click the link in the message to update your email address.",
"account.settings.field.email.help.text": "You receive messages from {siteName} and course teams at this address.",
"account.settings.field.secondary.email": "Recovery email address",
"account.settings.field.secondary.email.empty": "Add a recovery email address",
"account.settings.field.secondary.email.confirmation": "Weve sent a confirmation message to {value}. Click the link in the message to update your recovery email address.",
"account.settings.email.field.confirmation.header": "Pending confirmation",
"account.settings.field.dob": "Year of birth",
"account.settings.field.dob.empty": "Add year of birth",
"account.settings.field.year_of_birth.options.empty": "Select a year of birth",
"account.settings.field.dob.month": "Month",
"account.settings.field.dob.year": "Year",
"account.settings.field.dob.form.button": "Please confirm your date of birth",
"account.settings.field.dob.form.title": "Confirm your date of birth",
"account.settings.field.dob.form.help.text": "We ask for birth date information to help us comply with our legal obligations.",
"account.settings.field.dob.form.success": "Thank you for entering your birth date information.",
"account.settings.field.month_of_birth.options.empty": "Select a month of birth",
"account.settingsfield.dob.error.general": "A technical error occurred. Please try again.",
"account.settings.field.country": "Country",
"account.settings.field.country.empty": "Add country",
"account.settings.field.country.options.empty": "Select a Country",
"account.settings.field.state": "State",
"account.settings.field.state.empty": "Add state",
"account.settings.field.state.options.empty": "Select a State",
"account.settings.field.site.language": "Site language",
"account.settings.field.site.language.help.text": "The language used throughout this site. This site is currently available in a limited number of languages.",
"account.settings.field.education": "Education",
"account.settings.field.education.empty": "Add level of education",
"account.settings.field.education.levels.empty": "Select a level of education",
"account.settings.field.education.levels.p": "Doctorate",
"account.settings.field.education.levels.m": "Master's or professional degree",
"account.settings.field.education.levels.b": "Bachelor's Degree",
"account.settings.field.education.levels.a": "Associate's degree",
"account.settings.field.education.levels.hs": "Secondary/high school",
"account.settings.field.education.levels.jhs": "Junior secondary/junior high/middle school",
"account.settings.field.education.levels.el": "Elementary/primary school",
"account.settings.field.education.levels.none": "No formal education",
"account.settings.field.education.levels.o": "Other education",
"account.settings.field.gender": "Gender",
"account.settings.field.gender.empty": "Add gender",
"account.settings.field.gender.options.empty": "Select a gender",
"account.settings.field.gender.options.f": "Female",
"account.settings.field.gender.options.m": "Male",
"account.settings.field.gender.options.o": "Other",
"account.settings.field.language.proficiencies": "Spoken language",
"account.settings.field.language.proficiencies.empty": "Add a spoken language",
"account.settings.field.language_proficiencies.options.empty": "Select a Language",
"account.settings.field.time.zone": "Time zone",
"account.settings.field.time.zone.empty": "Set time zone",
"account.settings.field.time.zone.description": "Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browsers local time zone.",
"account.settings.field.time.zone.default": "Default (Local Time Zone)",
"account.settings.field.time.zone.all": "All time zones",
"account.settings.field.time.zone.country": "Country time zones",
"account.settings.section.social.media": "Social Media Links",
"account.settings.section.social.media.description": "Optionally, link your personal accounts to the social media icons on your {siteName} profile.",
"account.settings.field.social.platform.name.linkedin": "LinkedIn",
"account.settings.field.social.platform.name.linkedin.empty": "Add LinkedIn profile",
"account.settings.jump.nav.delete.account": "Delete My Account",
"account.settings.field.social.platform.name.twitter": "Twitter",
"account.settings.field.social.platform.name.twitter.empty": "Add Twitter profile",
"account.settings.field.social.platform.name.facebook": "Facebook",
"account.settings.field.social.platform.name.facebook.empty": "Add Facebook profile",
"account.settings.editable.field.action.save": "Save",
"account.settings.editable.field.action.cancel": "Cancel",
"account.settings.editable.field.action.edit": "Edit",
"account.settings.static.field.empty": "No value set. Contact your {enterprise} administrator to make changes.",
"account.settings.static.field.empty.no.admin": "No value set.",
"account.settings.field.name.certificate.select": "If checked, this name will appear on your certificates and public-facing records.",
"account.settings.field.name.modal.certificate.title": "Choose a preferred name for certificates and public-facing records",
"account.settings.field.name.modal.certificate.select": "Select a name",
"account.settings.field.name.modal.certificate.option.full": "Full Name",
"account.settings.field.name.modal.certificate.option.verified": "Verified Name",
"account.settings.field.name.modal.certificate.button.choose": "Choose name",
"account.settings.coaching.consent.welcome.header": "Lets get started.",
"account.settings.coaching.consent.welcome.subheader": "We're here for you from start to finish",
"account.settings.coaching.consent.description": "MicroBachelors programs include coaching that focuses on your career, education, and how you'll achieve results through one-on-one communication with an experienced professional. If youre interested, provide the information below and click “Submit,” and our coaching partner will connect with you via email and/or text message to help you move forward. Terms and conditions apply.*",
"account.settings.coaching.consent.text-messaging.disclaimer": "* Coaching services are included at no additional cost to learners with US phone numbers. Coaching includes recurring text messages. Message and data rates may apply. Text STOP to opt-out.",
"account.settings.coaching.consent.accept-coaching": "Sign up for coaching",
"account.settings.coaching.consent.decline-coaching": "I prefer not to be contacted with free coaching services",
"account.settings.coaching.consent.label.name": "Please confirm your name",
"account.settings.coaching.consent.label.phone-number": "Enter your mobile number",
"account.settings.coaching.consent.success.header": "Success!",
"account.settings.coaching.consent.success.message": "You're signed up for coaching. You can expect a message via email or SMS in the coming days.",
"account.settings.coaching.consent.success.continue": "Start my course",
"account.settings.coaching.managed.support": "support",
"account.settings.coaching.managed.alert": "Your name is managed by {managerTitle}. Contact your administrator for help.",
"account.settings.field.phone_number": "Phone Number",
"account.settings.field.phone_number.empty": "Add a phone number",
"account.settings.field.coaching_consent": "Coaching consent",
"account.settings.field.coaching_consent.tooltip": "MicroBachelors programs include text message based coaching that helps you pair educational experiences with your career goals through one-on-one advice. Coaching services are included at no additional cost, and are available to learners with U.S. mobile phone numbers. Standard messaging rates apply. Text STOP at anytime to opt-out of messages.",
"account.settings.field.coaching_consent.error": "A valid US phone number is required to opt into coaching",
"account.settings.delete.account.before.proceeding": "Before proceeding, please {actionLink}.",
"account.settings.delete.account.header": "Delete My Account",
"account.settings.delete.account.subheader": "We're sorry to see you go!",
"account.settings.delete.account.text.1": "Please note: Deletion of your account and personal data is permanent and cannot be undone. {siteName} will not be able to recover your account or the data that is deleted.",
"account.settings.delete.account.text.2": "Once your account is deleted, you cannot use it to take courses on {siteName}.",
"account.settings.delete.account.text.2.edX": "Once your account is deleted, you cannot use it to take courses on the edX app, edx.org, or any other site hosted by edX. This includes access to edx.org from your employers or universitys system and access to private sites offered by MIT Open Learning, Wharton Executive Education, and Harvard Medical School.",
"account.settings.delete.account.text.3.link": "Follow these instructions for printing or downloading a certificate",
"account.settings.delete.account.text.warning": "Warning: Account deletion is permanent. Please read the above carefully before proceeding. This is an irreversible action, and you will no longer be able to use the same email on {siteName}.",
"account.settings.delete.account.text.change.instead": "Want to change your email, name, or password instead?",
"account.settings.delete.account.button": "Delete My Account",
"account.settings.delete.account.please.activate": "activate your account",
"account.settings.delete.account.please.confirm": "confirm your account",
"account.settings.delete.account.please.unlink": "unlink all social media accounts",
"account.settings.delete.account.modal.header": "Are you sure?",
"account.settings.delete.account.modal.text.1": "You have selected \"Delete My Account\". Deletion of your account and personal data is permanent and cannot be undone. {siteName} will not be able to recover your account or the data that is deleted.",
"account.settings.delete.account.modal.text.2": "If you proceed, you will be unable to use this account to take courses on {siteName}.",
"account.settings.delete.account.modal.text.2.edX": "If you proceed, you will be unable to use this account to take courses on the edX app, edx.org, or any other site hosted by edX. This includes access to edx.org from your employer's or university's system and access to private sites offered by MIT Open Learning, Wharton Executive Education, and Harvard Medical School.",
"account.settings.delete.account.modal.enter.password": "If you still wish to continue and delete your account, please enter your account password:",
"account.settings.delete.account.modal.confirm.delete": "Yes, Delete",
"account.settings.delete.account.modal.confirm.cancel": "Cancel",
"account.settings.delete.account.error.unable.to.delete": "Unable to delete account",
"account.settings.delete.account.error.no.password": "A password is required",
"account.settings.delete.account.error.invalid.password": "Password is incorrect",
"account.settings.delete.account.error.unable.to.delete.details": "Sorry, there was an error trying to process your request. Please try again later.",
"account.settings.delete.account.modal.after.header": "We're sorry to see you go! Your account will be deleted shortly.",
"account.settings.delete.account.modal.after.text": "Account deletion, including removal from email lists, may take a few weeks to fully process through our system. If you want to opt-out of emails before then, please unsubscribe from the footer of any email.",
"account.settings.delete.account.modal.after.button": "Close",
"account.settings.delete.account.text.3.edX": "You may also lose access to verified certificates and other program credentials like MicroMasters certificates. You can make a copy of these for your records before proceeding with deletion. {actionLink}.",
"account.settings.delete.account.text.3": "You may also lose access to verified certificates and other program credentials. You can make a copy of these for your records before proceeding with deletion.",
"account.settings.message.demographics.service.issue": "An error occurred attempting to retrieve or save your account information. Please try again later.",
"account.settings.field.demographics.gender": "Gender identity",
"account.settings.field.demographics.gender.empty": "Add gender identity",
"account.settings.field.demographics.gender.options.empty": "Select a gender identity",
"account.settings.field.demographics.gender_description": "Gender identity description",
"account.settings.field.demographics.gender_description.empty": "Enter description",
"account.settings.field.demographics.ethnicity": "Race/Ethnicity identity",
"account.settings.field.demographics.ethnicity.empty": "Add race/ethnicity identity",
"account.settings.field.demographics.ethnicity.options.empty": "Select all that apply",
"account.settings.field.demographics.income": "Family income",
"account.settings.field.demographics.income.empty": "Add family income",
"account.settings.field.demographics.income.options.empty": "Select a family income range",
"account.settings.field.demographics.military_history": "U.S. Military status",
"account.settings.field.demographics.military_history.empty": "Add military status",
"account.settings.field.demographics.military_history.options.empty": "Select military status",
"account.settings.field.demographics.learner_education_level": "Your education level",
"account.settings.field.demographics.learner_education_level.empty": "Add education level",
"account.settings.field.demographics.parent_education_level": "Parents/Guardians education level",
"account.settings.field.demographics.parent_education_level.empty": "Add education level",
"account.settings.field.demographics.education_level.options.empty": "Select education level",
"account.settings.field.demographics.work_status": "Employment status",
"account.settings.field.demographics.work_status.empty": "Add employment status",
"account.settings.field.demographics.work_status.options.empty": "Select employment status",
"account.settings.field.demographics.work_status_description": "Employment status description",
"account.settings.field.demographics.work_status_description.empty": "Enter description",
"account.settings.field.demographics.current_work_sector": "Current work industry",
"account.settings.field.demographics.current_work_sector.empty": "Add work industry",
"account.settings.field.demographics.future_work_sector": "Future work industry",
"account.settings.field.demographics.future_work_sector.empty": "Add work industry",
"account.settings.field.demographics.work_sector.options.empty": "Select work industry",
"account.settings.section.demographics.why": "Why does {siteName} collect this information?",
"account.settings.name.change.title.id": "This name change requires identity verification",
"account.settings.name.change.title.begin": "Before we begin",
"account.settings.name.change.warning.one": "Warning: This action updates the name that appears on all certificates that have been earned on this account in the past and any certificates you are currently earning or will earn in the future.",
"account.settings.name.change.warning.two": "This action cannot be undone without verifying your identity.",
"account.settings.name.change.id.name.label": "Enter your name as it appears on your unexpired student, work, or government-issued identification card.",
"account.settings.name.change.id.name.placeholder": "Enter the name on your photo ID",
"account.settings.name.change.error.valid.name": "Please enter a valid name.",
"account.settings.name.change.error.general": "A technical error occurred. Please try again.",
"account.settings.name.change.continue": "Continue",
"account.settings.name.change.cancel": "Cancel",
"error.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.",
"account.settings.editable.field.password.reset.button.confirmation.support.link": "technical support",
"account.settings.editable.field.password.reset.button.confirmation": "We've sent a message to {email}. Click the link in the message to reset your password. Didn't receive the message? Contact {technicalSupportLink}.",
"account.settings.editable.field.password.reset.button": "Reset Password",
"account.settings.editable.field.password.reset.button.forbidden": "Your previous request is in progress, please try again in few moments.",
"account.settings.editable.field.password.reset.label": "Password",
"account.settings.sso.link.account": "Sign in with {name}",
"account.settings.sso.account.connected": "Linked",
"account.settings.sso.account.disconnect.error": "There was a problem disconnecting this account. Contact support if the problem persists.",
"account.settings.sso.unlink.account": "Unlink {name} account",
"account.settings.sso.no.providers": "No accounts can be linked at this time.",
"account.page.title": "Account | {siteName}",
"id.verification.access.blocked.denied": "We cannot verify your identity at this time. If you have yet to activate your account, please check your spam folder for the activation email from {email}.",
"id.verification.next": "Next",
"id.verification.support": "support",
"id.verification.example.card.alt": "Example of a valid identification card with a full name and photo.",
"id.verification.requirements.title": "Photo Verification Requirements",
"id.verification.requirements.description": "In order to complete Photo Verification, you will need the following:",
"id.verification.requirements.card.device.title": "Device with Camera",
"id.verification.requirements.card.device.allow": "Allow",
"id.verification.requirements.card.id.title": "Photo Identification Card",
"id.verification.requirements.card.id.text": "You need a valid identification card that contains your full name and photo, such as a drivers license or passport.",
"id.verification.privacy.title": "Privacy Information",
"id.verification.privacy.need.photo.question": "Why does {siteName} need my photo?",
"id.verification.privacy.need.photo.answer": "We use your verification photos to confirm your identity and ensure the validity of your certificate.",
"id.verification.privacy.do.with.photo.question": "What does {siteName} do with this photo?",
"id.verification.privacy.do.with.photo.answer": "We securely encrypt your photo and send it our authorization service for review. Your photo and information are not saved or visible anywhere on {siteName} after the verification process is complete.",
"id.verification.access.blocked.title": "Identity Verification",
"id.verification.access.blocked.enrollment": "You are not currently enrolled in a course that requires identity verification.",
"id.verification.access.blocked.pending": "You have already submitted your verification information. You will see a message on your dashboard when the verification process is complete (usually within 5 days).",
"id.verification.photo.take": "Take Photo",
"id.verification.photo.retake": "Retake Photo?",
"id.verification.photo.enable.detection": "Enable Face Detection",
"id.verification.photo.enable.detection.portrait.help.text": "If checked, a box will appear around your face. Your face can be seen clearly if the box around it is blue. If your face is not in a good position or undetectable, the box will be red.",
"id.verification.photo.enable.detection.id.help.text": "If checked, a box will appear around the face on your ID card. The face can be seen clearly if the box around it is blue. If the face is not in a good position or undetectable, the box will be red.",
"id.verification.photo.feedback.correct": "Face is in a good position.",
"id.verification.photo.feedback.two.faces": "More than one face detected.",
"id.verification.photo.feedback.no.faces": "No face detected.",
"id.verification.photo.feedback.top.left": "Incorrect position. Top left.",
"id.verification.photo.feedback.top.center": "Incorrect position. Top center.",
"id.verification.photo.feedback.top.right": "Incorrect position. Top right.",
"id.verification.photo.feedback.center.left": "Incorrect position. Center left.",
"id.verification.photo.feedback.center.center": "Incorrect position. Too close to camera.",
"id.verification.photo.feedback.center.right": "Incorrect position. Center right.",
"id.verification.photo.feedback.bottom.left": "Incorrect position. Bottom left.",
"id.verification.photo.feedback.bottom.center": "Incorrect position. Bottom center.",
"id.verification.photo.feedback.bottom.right": "Incorrect position. Bottom right.",
"id.verification.camera.access.title": "Camera Permissions",
"id.verification.camera.access.title.success": "Camera Access Enabled",
"id.verification.camera.access.title.failed": "Camera Access Failed",
"id.verification.camera.access.click.allow": "Please make sure to click \"Allow\"",
"id.verification.camera.access.enable": "Enable Camera",
"id.verification.camera.access.problems": "Having problems?",
"id.verification.camera.access.skip": "Skip and upload image files instead",
"id.verification.camera.access.success": "Looks like your camera is working and ready.",
"id.verification.camera.access.failure": "It looks like we're unable to access your camera. You will need to upload image files of you and your photo id.",
"id.verification.camera.access.failure.temporary": "It looks like we're unable to access your camera. Please verify that your webcam is connected and that you have allowed your browser to access it.",
"id.verification.camera.access.failure.temporary.chrome": "To enable camera access in Chrome:",
"id.verification.camera.access.failure.temporary.chrome.step1": "Open Chrome.",
"id.verification.camera.access.failure.temporary.chrome.step2": "Navigate to More > Settings.",
"id.verification.camera.access.failure.temporary.chrome.step2.windows": "For Windows: Alt+F, Alt+E, or F10 followed by the spacebar",
"id.verification.camera.access.failure.temporary.chrome.step2.mac": "For Mac: Command+,",
"id.verification.camera.access.failure.temporary.chrome.step3": "Under the \"Privacy and security\" tab, select \"Site Settings\" and then \"Camera.\"",
"id.verification.camera.access.failure.temporary.chrome.step4": "Under \"Blocked,\" find \"edx.org\" and select it.",
"id.verification.camera.access.failure.temporary.chrome.step5": "In the \"Permissions\" section, update the camera permissions to \"Allow.\"",
"id.verification.camera.access.failure.temporary.ie11": "To enable camera access in Internet Explorer:",
"id.verification.camera.access.failure.temporary.ie11.step1": "Open the Flash Player Settings Manager by navigating to Windows Settings > Control Panel > Flash Player.",
"id.verification.camera.access.failure.temporary.ie11.step2": "Select the \"Camera and Mic\" tab, and then select the \"Camera and Microphone Settings by Site\" button.",
"id.verification.camera.access.failure.temporary.ie11.step3": "Choose \"edx.org\" from the list of websites and change the permissions by selecting \"Allow\" in the dropdown menu.",
"id.verification.camera.access.failure.temporary.firefox": "To enable camera access in Firefox:",
"id.verification.camera.access.failure.temporary.firefox.step1": "Open Firefox.",
"id.verification.camera.access.failure.temporary.firefox.step2": "Enter \"about:preferences\" in the URL bar.",
"id.verification.camera.access.failure.temporary.firefox.step3": "Select the \"Privacy & Security\" tab, and navigate to the \"Permissions\" section.",
"id.verification.camera.access.failure.temporary.firefox.step4": "Next to \"Camera,\" select the \"Settings…\" button.",
"id.verification.camera.access.failure.temporary.firefox.step5": "In the search bar, enter \"edx.org.\"",
"id.verification.camera.access.failure.temporary.firefox.step6": "In the status column for \"edx.org,\" select \"Allow\" from the drop down.",
"id.verification.camera.access.failure.temporary.firefox.step7": "Select \"Save Changes.\"",
"id.verification.camera.access.failure.temporary.safari": "To enable camera access in Safari:",
"id.verification.camera.access.failure.temporary.safari.step1": "Open Safari.",
"id.verification.camera.access.failure.temporary.safari.step2": "Click on the Safari app menu, then select \"Preferences.\" You can also use Command+, as a keyboard shortcut.",
"id.verification.camera.access.failure.temporary.safari.step3": "Select the \"Websites\" tab and then select \"Camera.\"",
"id.verification.camera.access.failure.temporary.safari.step4": "Select \"edx.org\" and change the camera permissions to \"Allow.\"",
"id.verification.camera.access.failure.unsupported": "It looks like your browser does not support camera access.",
"id.verification.camera.access.failure.unsupported.chrome.explanation": "The Chrome browser currently does not support camera access on iOS devices, such as iPhones and iPads.",
"id.verification.camera.access.failure.unsupported.instructions": "Please use another browser to complete Identity Verification.",
"id.verification.photo.tips.title": "Helpful Photo Tips",
"id.verification.photo.tips.description": "Next, we'll need you to take a photo of your face. Please review the helpful tips below.",
"id.verification.photo.tips.list.title": "Photo Tips",
"id.verification.photo.tips.list.description": "To take a successful photo, make sure that:",
"id.verification.photo.tips.list.well.lit": "Your face is well-lit.",
"id.verification.photo.tips.list.inside.frame": "Your entire face fits inside the frame.",
"id.verification.portrait.photo.title.camera": "Take a Photo of Yourself",
"id.verification.portrait.photo.instructions.camera": "When your face is in position, use the Take Photo button below to take your photo.",
"id.verification.camera.help.sight.question": "What if I can't see the camera image or if I can't see my photo to determine which side is visible?",
"id.verification.camera.help.sight.answer.portrait": "You may be able to complete the image capture procedure without assistance, but it may take a couple of submission attempts to get the camera positioning right. Optimal camera positioning varies with each computer, but generally the best position for a headshot is approximately 12-18 inches (30-45 centimeters) from the camera, with your head centered relative to the computer screen. If the photos you submit are rejected, try moving the computer or camera orientation to change the lighting angle.",
"id.verification.camera.help.sight.answer.id": "You may be able to complete the image capture procedure without assistance, but it may take a couple of submission attempts to get the camera positioning right. Optimal camera positioning varies with each computer, but generally, the best position for a photo of an ID card is 8-12 inches (20-30 centimeters) from the camera, with the ID card centered relative to the camera. If the photos you submit are rejected, try moving the computer or camera orientation to change the lighting angle. The most common reason for rejection is inability to read the text on the ID card.",
"id.verification.camera.help.difficulty.question.portrait": "What if I have difficulty holding my head in position relative to the camera?",
"id.verification.camera.help.difficulty.question.id": "What if I have difficulty holding my ID in position relative to the camera?",
"id.verification.camera.help.difficulty.answer": "If you require assistance with taking a photo for submission, contact {siteName} support for additional suggestions.",
"id.verification.id.photo.unclear.question": "Is your ID card image not clear or too blurry?",
"id.verification.id.tips.title": "Helpful Identification Card Tips",
"id.verification.id.tips.description": "Next, we'll need you to take a photo of a valid identification card that includes your full name and photo, such as a drivers license or passport. Please have your ID ready.",
"id.verification.id.tips.list.well.lit": "Your identification card is well-lit.",
"id.verification.id.tips.list.clear": "Ensure that you can see your photo and clearly read your name.",
"id.verification.id.photo.title.camera": "Take a Photo of Your Identification Card",
"id.verification.id.photo.title.upload": "Upload a Photo of Your Identification Card",
"id.verification.id.photo.preview.alt": "Preview of photo ID.",
"id.verification.id.photo.instructions.camera": "When your ID is in position, use the Take Photo button below to take your photo. Please use a passport, drivers license, or another identification card that includes your full name and a picture of your face.",
"id.verification.id.photo.instructions.upload": "Please upload a photo of your identification card. Ensure the entire ID fits inside the frame and is well-lit. The file size must be under 10 MB. Supported formats: ",
"id.verification.id.photo.instructions.upload.error.invalidFileType": "The file you have selected is not a supported image type. Please choose from the following formats: ",
"id.verification.id.photo.instructions.upload.error.fileTooLarge": "The file you have selected is too large. Please try again with a file less than 10MB.",
"id.verification.name.check.title": "Double-Check Your Name",
"id.verification.name.check.instructions": "Does the name below match the name on your photo ID? If not, update the name below to match your photo ID.",
"id.verification.name.check.mismatch.information": "If the name below does not match your photo ID, your identity verification will be denied.",
"id.verification.name.error": "Please enter your name as it appears on your photo ID.",
"id.verification.account.name.warning.prefix": "Please Note:",
"id.verification.account.name.settings": "Account Settings",
"id.verification.name.label": "Name",
"id.verification.account.name.photo.alt": "Photo of your ID to be submitted.",
"id.verification.review.title": "Review Your Photos",
"id.verification.review.description": "Make sure we can verify your identity with the photos and information you have provided.",
"id.verification.review.portrait.label": "Your Portrait",
"id.verification.review.portrait.alt": "Photo of your face to be submitted.",
"id.verification.review.portrait.retake": "Retake Portrait Photo",
"id.verification.review.id.label": "Your Identification Card",
"id.verification.review.id.alt": "Photo of your identification card to be submitted.",
"id.verification.review.id.retake": "Retake ID Photo",
"id.verification.review.confirm": "Submit",
"id.verification.submission.alert.error.face": "A photo of your face is required. Please retake your portrait photo.",
"id.verification.submission.alert.error.id": "A photo of your ID card is required. Please retake your ID photo.",
"id.verification.submission.alert.error.name": "A valid account name is required. Please update your account name to match the name on your ID.",
"id.verification.submission.alert.error.unsupported": "One or more of the files you have uploaded is in an unsupported format. Please choose from the following: ",
"id.verification.review.error": "{siteName} Support Page",
"id.verification.submitted.title": "Identity Verification in Progress",
"id.verification.submitted.text": "We have received your information and are verifying your identity. You will be notified when the verification process is complete (usually within 5 days). In the meantime, you can still access all available course content.",
"id.verification.return.dashboard": "Return to Your Dashboard",
"id.verification.return.course": "Return to Course",
"id.verification.return.generic": "Return",
"id.verification.photo.upload.help.title": "Upload a Photo Instead",
"id.verification.photo.camera.help.title": "Use Your Camera Instead",
"id.verification.photo.upload.help.text": "If you are having trouble using the photo capture above, you may want to upload a photo instead. To upload a photo, click the button below.",
"id.verification.photo.camera.help.text": "If you are having trouble uploading a photo above, you may want to use your camera instead. To use your camera, click the button below.",
"id.verification.upload.help.button": "Switch to Upload Mode",
"id.verification.camera.help.button": "Switch to Camera Mode",
"id.verification.request.camera.access.instructions": "In order to take a photo using your webcam, you may receive a browser prompt for access to your camera. {clickAllow}",
"id.verification.requirements.account.managed.alert": "Your account settings are managed by {managerTitle}. If the name on your photo ID does not match the name on your account, please contact your {profileDataManager} administrator or {support} for help before completing the Photo Verification process.",
"id.verification.requirements.card.device.text": "You need a device that has a camera. If you receive a browser prompt for access to your camera, please make sure to click {allow}.",
"id.verification.account.name.summary.alert": "Your account settings are managed by {managerTitle}. If the name on your photo ID does not match the name on your account, please contact your {profileDataManager} administrator or {support} for help.",
"idv.submission.alert.error": "\n We encountered a technical error while trying to submit ID verification.\n This might be a temporary issue, so please try again in a few minutes.\n If the problem persists, please go to {support_link} for help.\n ",
"id.verification.account.name.edit": "Edit {sr}"
}

Some files were not shown because too many files have changed in this diff Show More