diff --git a/.env.development b/.env.development index 8d46db06..5e9012fc 100644 --- a/.env.development +++ b/.env.development @@ -19,3 +19,4 @@ PRIVACY_POLICY='http://localhost:18000/privacy' LOGIN_ISSUE_SUPPORT_LINK='http://localhost:18000/login-issue-support-url' # ***** Cookies ***** USER_RETENTION_COOKIE_NAME='authn-returning-user' +LANGUAGE_PREFERENCE_COOKIE_NAME='openedx-language-preference' diff --git a/.gitignore b/.gitignore index bab04097..1cfced7f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ .cache .DS_Store coverage -dist node_modules temp src/i18n/transifex_input.json diff --git a/dist/LICENSE b/dist/LICENSE new file mode 100644 index 00000000..0ad25db4 --- /dev/null +++ b/dist/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/dist/README.md b/dist/README.md new file mode 100644 index 00000000..f7fc2138 --- /dev/null +++ b/dist/README.md @@ -0,0 +1 @@ +# frontend-component-authn-edx \ No newline at end of file diff --git a/dist/authn-component/data/reducers.js b/dist/authn-component/data/reducers.js new file mode 100644 index 00000000..00f5d70f --- /dev/null +++ b/dist/authn-component/data/reducers.js @@ -0,0 +1,65 @@ +/** + * Redux slice for managing authn component common state i.e, providers, current providers, etc + */ + +import { createSlice } from '@reduxjs/toolkit'; +import { COMPLETE_STATE, DEFAULT_STATE, FAILURE_STATE, PENDING_STATE } from '../../data/constants'; +export const commonDataStoreName = 'commonData'; +export const COMMON_DATA_SLICE_NAME = 'commonData'; +export const commonDataInitialState = { + onboardingComponentContext: {}, + currentForm: null, + thirdPartyAuthApiStatus: DEFAULT_STATE, + thirdPartyAuthContext: { + autoSubmitRegForm: false, + currentProvider: null, + countryCode: null, + finishAuthUrl: null, + providers: [], + secondaryProviders: [], + pipelineUserDetails: null, + errorMessage: null + } +}; +export const commonDataSlice = createSlice({ + name: COMMON_DATA_SLICE_NAME, + initialState: commonDataInitialState, + reducers: { + setOnboardingComponentContext: (state, _ref) => { + let { + payload: componentContext + } = _ref; + state.onboardingComponentContext = componentContext; + }, + getThirdPartyAuthContext: state => { + state.thirdPartyAuthApiStatus = PENDING_STATE; + }, + getThirdPartyAuthContextSuccess: (state, _ref2) => { + let { + payload: thirdPartyAuthContextData + } = _ref2; + state.thirdPartyAuthApiStatus = COMPLETE_STATE; + state.thirdPartyAuthContext = thirdPartyAuthContextData; + }, + getThirdPartyAuthContextFailed: state => { + state.thirdPartyAuthApiStatus = FAILURE_STATE; + state.thirdPartyAuthContext.errorMessage = null; + }, + setCurrentOpenedForm: (state, _ref3) => { + let { + payload: currentForm + } = _ref3; + state.currentForm = currentForm; + state.thirdPartyAuthContext.errorMessage = null; + } + } +}); +export const { + setOnboardingComponentContext, + getThirdPartyAuthContext, + getThirdPartyAuthContextSuccess, + getThirdPartyAuthContextFailed, + setCurrentOpenedForm +} = commonDataSlice.actions; +export default commonDataSlice.reducer; +//# sourceMappingURL=reducers.js.map \ No newline at end of file diff --git a/dist/authn-component/data/reducers.js.map b/dist/authn-component/data/reducers.js.map new file mode 100644 index 00000000..13073013 --- /dev/null +++ b/dist/authn-component/data/reducers.js.map @@ -0,0 +1 @@ +{"version":3,"file":"reducers.js","names":["createSlice","COMPLETE_STATE","DEFAULT_STATE","FAILURE_STATE","PENDING_STATE","commonDataStoreName","COMMON_DATA_SLICE_NAME","commonDataInitialState","onboardingComponentContext","currentForm","thirdPartyAuthApiStatus","thirdPartyAuthContext","autoSubmitRegForm","currentProvider","countryCode","finishAuthUrl","providers","secondaryProviders","pipelineUserDetails","errorMessage","commonDataSlice","name","initialState","reducers","setOnboardingComponentContext","state","_ref","payload","componentContext","getThirdPartyAuthContext","getThirdPartyAuthContextSuccess","_ref2","thirdPartyAuthContextData","getThirdPartyAuthContextFailed","setCurrentOpenedForm","_ref3","actions","reducer"],"sources":["../../../src/authn-component/data/reducers.js"],"sourcesContent":["/**\n * Redux slice for managing authn component common state i.e, providers, current providers, etc\n */\n\nimport { createSlice } from '@reduxjs/toolkit';\n\nimport {\n COMPLETE_STATE, DEFAULT_STATE, FAILURE_STATE, PENDING_STATE,\n} from '../../data/constants';\n\nexport const commonDataStoreName = 'commonData';\nexport const COMMON_DATA_SLICE_NAME = 'commonData';\n\nexport const commonDataInitialState = {\n onboardingComponentContext: {},\n currentForm: null,\n thirdPartyAuthApiStatus: DEFAULT_STATE,\n thirdPartyAuthContext: {\n autoSubmitRegForm: false,\n currentProvider: null,\n countryCode: null,\n finishAuthUrl: null,\n providers: [],\n secondaryProviders: [],\n pipelineUserDetails: null,\n errorMessage: null,\n },\n};\n\nexport const commonDataSlice = createSlice({\n name: COMMON_DATA_SLICE_NAME,\n initialState: commonDataInitialState,\n reducers: {\n setOnboardingComponentContext: (state, { payload: componentContext }) => {\n state.onboardingComponentContext = componentContext;\n },\n getThirdPartyAuthContext: (state) => {\n state.thirdPartyAuthApiStatus = PENDING_STATE;\n },\n getThirdPartyAuthContextSuccess: (state, { payload: thirdPartyAuthContextData }) => {\n state.thirdPartyAuthApiStatus = COMPLETE_STATE;\n state.thirdPartyAuthContext = thirdPartyAuthContextData;\n },\n getThirdPartyAuthContextFailed: (state) => {\n state.thirdPartyAuthApiStatus = FAILURE_STATE;\n state.thirdPartyAuthContext.errorMessage = null;\n },\n setCurrentOpenedForm: (state, { payload: currentForm }) => {\n state.currentForm = currentForm;\n state.thirdPartyAuthContext.errorMessage = null;\n },\n },\n});\n\nexport const {\n setOnboardingComponentContext,\n getThirdPartyAuthContext,\n getThirdPartyAuthContextSuccess,\n getThirdPartyAuthContextFailed,\n setCurrentOpenedForm,\n} = commonDataSlice.actions;\n\nexport default commonDataSlice.reducer;\n"],"mappings":"AAAA;AACA;AACA;;AAEA,SAASA,WAAW,QAAQ,kBAAkB;AAE9C,SACEC,cAAc,EAAEC,aAAa,EAAEC,aAAa,EAAEC,aAAa,QACtD,sBAAsB;AAE7B,OAAO,MAAMC,mBAAmB,GAAG,YAAY;AAC/C,OAAO,MAAMC,sBAAsB,GAAG,YAAY;AAElD,OAAO,MAAMC,sBAAsB,GAAG;EACpCC,0BAA0B,EAAE,CAAC,CAAC;EAC9BC,WAAW,EAAE,IAAI;EACjBC,uBAAuB,EAAER,aAAa;EACtCS,qBAAqB,EAAE;IACrBC,iBAAiB,EAAE,KAAK;IACxBC,eAAe,EAAE,IAAI;IACrBC,WAAW,EAAE,IAAI;IACjBC,aAAa,EAAE,IAAI;IACnBC,SAAS,EAAE,EAAE;IACbC,kBAAkB,EAAE,EAAE;IACtBC,mBAAmB,EAAE,IAAI;IACzBC,YAAY,EAAE;EAChB;AACF,CAAC;AAED,OAAO,MAAMC,eAAe,GAAGpB,WAAW,CAAC;EACzCqB,IAAI,EAAEf,sBAAsB;EAC5BgB,YAAY,EAAEf,sBAAsB;EACpCgB,QAAQ,EAAE;IACRC,6BAA6B,EAAEA,CAACC,KAAK,EAAAC,IAAA,KAAoC;MAAA,IAAlC;QAAEC,OAAO,EAAEC;MAAiB,CAAC,GAAAF,IAAA;MAClED,KAAK,CAACjB,0BAA0B,GAAGoB,gBAAgB;IACrD,CAAC;IACDC,wBAAwB,EAAGJ,KAAK,IAAK;MACnCA,KAAK,CAACf,uBAAuB,GAAGN,aAAa;IAC/C,CAAC;IACD0B,+BAA+B,EAAEA,CAACL,KAAK,EAAAM,KAAA,KAA6C;MAAA,IAA3C;QAAEJ,OAAO,EAAEK;MAA0B,CAAC,GAAAD,KAAA;MAC7EN,KAAK,CAACf,uBAAuB,GAAGT,cAAc;MAC9CwB,KAAK,CAACd,qBAAqB,GAAGqB,yBAAyB;IACzD,CAAC;IACDC,8BAA8B,EAAGR,KAAK,IAAK;MACzCA,KAAK,CAACf,uBAAuB,GAAGP,aAAa;MAC7CsB,KAAK,CAACd,qBAAqB,CAACQ,YAAY,GAAG,IAAI;IACjD,CAAC;IACDe,oBAAoB,EAAEA,CAACT,KAAK,EAAAU,KAAA,KAA+B;MAAA,IAA7B;QAAER,OAAO,EAAElB;MAAY,CAAC,GAAA0B,KAAA;MACpDV,KAAK,CAAChB,WAAW,GAAGA,WAAW;MAC/BgB,KAAK,CAACd,qBAAqB,CAACQ,YAAY,GAAG,IAAI;IACjD;EACF;AACF,CAAC,CAAC;AAEF,OAAO,MAAM;EACXK,6BAA6B;EAC7BK,wBAAwB;EACxBC,+BAA+B;EAC/BG,8BAA8B;EAC9BC;AACF,CAAC,GAAGd,eAAe,CAACgB,OAAO;AAE3B,eAAehB,eAAe,CAACiB,OAAO","ignoreList":[]} \ No newline at end of file diff --git a/dist/authn-component/data/sagas.js b/dist/authn-component/data/sagas.js new file mode 100644 index 00000000..8c283298 --- /dev/null +++ b/dist/authn-component/data/sagas.js @@ -0,0 +1,27 @@ +import { logError } from '@edx/frontend-platform/logging'; +import { call, put, takeEvery } from 'redux-saga/effects'; +import { getThirdPartyAuthContext, getThirdPartyAuthContextFailed, getThirdPartyAuthContextSuccess } from './reducers'; +import fetchThirdPartyAuthContext from './service'; + +/** + * Saga function for fetching third party auth context data. + */ +export function* fetchThirdPartyAuthContextSaga(action) { + try { + const { + thirdPartyAuthContext + } = yield call(fetchThirdPartyAuthContext, action.payload); + yield put(getThirdPartyAuthContextSuccess(thirdPartyAuthContext)); + } catch (e) { + yield put(getThirdPartyAuthContextFailed()); + logError(e); + } +} + +/** + * Root Saga function that listens for TPA actions and calls the fetchThirdPartyAuthContext saga. + */ +export default function* saga() { + yield takeEvery(getThirdPartyAuthContext.type, fetchThirdPartyAuthContextSaga); +} +//# sourceMappingURL=sagas.js.map \ No newline at end of file diff --git a/dist/authn-component/data/sagas.js.map b/dist/authn-component/data/sagas.js.map new file mode 100644 index 00000000..6a511bba --- /dev/null +++ b/dist/authn-component/data/sagas.js.map @@ -0,0 +1 @@ +{"version":3,"file":"sagas.js","names":["logError","call","put","takeEvery","getThirdPartyAuthContext","getThirdPartyAuthContextFailed","getThirdPartyAuthContextSuccess","fetchThirdPartyAuthContext","fetchThirdPartyAuthContextSaga","action","thirdPartyAuthContext","payload","e","saga","type"],"sources":["../../../src/authn-component/data/sagas.js"],"sourcesContent":["import { logError } from '@edx/frontend-platform/logging';\nimport { call, put, takeEvery } from 'redux-saga/effects';\n\nimport {\n getThirdPartyAuthContext,\n getThirdPartyAuthContextFailed,\n getThirdPartyAuthContextSuccess,\n} from './reducers';\nimport fetchThirdPartyAuthContext from './service';\n\n/**\n * Saga function for fetching third party auth context data.\n */\nexport function* fetchThirdPartyAuthContextSaga(action) {\n try {\n const { thirdPartyAuthContext } = yield call(fetchThirdPartyAuthContext, action.payload);\n\n yield put(getThirdPartyAuthContextSuccess(thirdPartyAuthContext));\n } catch (e) {\n yield put(getThirdPartyAuthContextFailed());\n logError(e);\n }\n}\n\n/**\n * Root Saga function that listens for TPA actions and calls the fetchThirdPartyAuthContext saga.\n */\nexport default function* saga() {\n yield takeEvery(getThirdPartyAuthContext.type, fetchThirdPartyAuthContextSaga);\n}\n"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,gCAAgC;AACzD,SAASC,IAAI,EAAEC,GAAG,EAAEC,SAAS,QAAQ,oBAAoB;AAEzD,SACEC,wBAAwB,EACxBC,8BAA8B,EAC9BC,+BAA+B,QAC1B,YAAY;AACnB,OAAOC,0BAA0B,MAAM,WAAW;;AAElD;AACA;AACA;AACA,OAAO,UAAUC,8BAA8BA,CAACC,MAAM,EAAE;EACtD,IAAI;IACF,MAAM;MAAEC;IAAsB,CAAC,GAAG,MAAMT,IAAI,CAACM,0BAA0B,EAAEE,MAAM,CAACE,OAAO,CAAC;IAExF,MAAMT,GAAG,CAACI,+BAA+B,CAACI,qBAAqB,CAAC,CAAC;EACnE,CAAC,CAAC,OAAOE,CAAC,EAAE;IACV,MAAMV,GAAG,CAACG,8BAA8B,CAAC,CAAC,CAAC;IAC3CL,QAAQ,CAACY,CAAC,CAAC;EACb;AACF;;AAEA;AACA;AACA;AACA,eAAe,UAAUC,IAAIA,CAAA,EAAG;EAC9B,MAAMV,SAAS,CAACC,wBAAwB,CAACU,IAAI,EAAEN,8BAA8B,CAAC;AAChF","ignoreList":[]} \ No newline at end of file diff --git a/dist/authn-component/data/selectors.js b/dist/authn-component/data/selectors.js new file mode 100644 index 00000000..08179e1e --- /dev/null +++ b/dist/authn-component/data/selectors.js @@ -0,0 +1,17 @@ +function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } +function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } +function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); } +function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } +import { createSelector } from 'reselect'; +const getProviders = state => state.commonData.thirdPartyAuthContext.providers; + +/** + * Selects and parses the providers list into an object where keys are provider names + * and values are the provider objects. + */ +const providersSelector = createSelector(getProviders, providers => providers.reduce((parsedProvidersList, provider) => _objectSpread(_objectSpread({}, parsedProvidersList), {}, { + [provider.name]: provider +}), {})); +export default providersSelector; +//# sourceMappingURL=selectors.js.map \ No newline at end of file diff --git a/dist/authn-component/data/selectors.js.map b/dist/authn-component/data/selectors.js.map new file mode 100644 index 00000000..2e048de1 --- /dev/null +++ b/dist/authn-component/data/selectors.js.map @@ -0,0 +1 @@ +{"version":3,"file":"selectors.js","names":["createSelector","getProviders","state","commonData","thirdPartyAuthContext","providers","providersSelector","reduce","parsedProvidersList","provider","_objectSpread","name"],"sources":["../../../src/authn-component/data/selectors.js"],"sourcesContent":["import { createSelector } from 'reselect';\n\nconst getProviders = state => state.commonData.thirdPartyAuthContext.providers;\n\n/**\n * Selects and parses the providers list into an object where keys are provider names\n * and values are the provider objects.\n */\nconst providersSelector = createSelector(\n getProviders,\n providers => providers.reduce(\n (parsedProvidersList, provider) => ({\n ...parsedProvidersList,\n [provider.name]: provider,\n }),\n {},\n ),\n);\n\nexport default providersSelector;\n"],"mappings":";;;;;AAAA,SAASA,cAAc,QAAQ,UAAU;AAEzC,MAAMC,YAAY,GAAGC,KAAK,IAAIA,KAAK,CAACC,UAAU,CAACC,qBAAqB,CAACC,SAAS;;AAE9E;AACA;AACA;AACA;AACA,MAAMC,iBAAiB,GAAGN,cAAc,CACtCC,YAAY,EACZI,SAAS,IAAIA,SAAS,CAACE,MAAM,CAC3B,CAACC,mBAAmB,EAAEC,QAAQ,KAAAC,aAAA,CAAAA,aAAA,KACzBF,mBAAmB;EACtB,CAACC,QAAQ,CAACE,IAAI,GAAGF;AAAQ,EACzB,EACF,CAAC,CACH,CACF,CAAC;AAED,eAAeH,iBAAiB","ignoreList":[]} \ No newline at end of file diff --git a/dist/authn-component/data/service.js b/dist/authn-component/data/service.js new file mode 100644 index 00000000..1c493f98 --- /dev/null +++ b/dist/authn-component/data/service.js @@ -0,0 +1,29 @@ +import { getConfig } from '@edx/frontend-platform'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; + +/** + * Fetches third-party authentication context data from the specified URL with the given parameters. + * + * @param {Object} urlParams - The URL parameters to include in the request. + * @returns {Object} An object containing the third-party authentication context data. + * @throws {Error} If the request fails. + */ +async function fetchThirdPartyAuthContext(urlParams) { + const requestConfig = { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + params: urlParams, + isPublic: true + }; + const { + data + } = await getAuthenticatedHttpClient().get(`${getConfig().LMS_BASE_URL}/api/mfe_context`, requestConfig).catch(e => { + throw e; + }); + return { + thirdPartyAuthContext: data.contextData || {} + }; +} +export default fetchThirdPartyAuthContext; +//# sourceMappingURL=service.js.map \ No newline at end of file diff --git a/dist/authn-component/data/service.js.map b/dist/authn-component/data/service.js.map new file mode 100644 index 00000000..17c6d5d3 --- /dev/null +++ b/dist/authn-component/data/service.js.map @@ -0,0 +1 @@ +{"version":3,"file":"service.js","names":["getConfig","getAuthenticatedHttpClient","fetchThirdPartyAuthContext","urlParams","requestConfig","headers","params","isPublic","data","get","LMS_BASE_URL","catch","e","thirdPartyAuthContext","contextData"],"sources":["../../../src/authn-component/data/service.js"],"sourcesContent":["import { getConfig } from '@edx/frontend-platform';\nimport { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';\n\n/**\n * Fetches third-party authentication context data from the specified URL with the given parameters.\n *\n * @param {Object} urlParams - The URL parameters to include in the request.\n * @returns {Object} An object containing the third-party authentication context data.\n * @throws {Error} If the request fails.\n */\nasync function fetchThirdPartyAuthContext(urlParams) {\n const requestConfig = {\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n params: urlParams,\n isPublic: true,\n };\n\n const { data } = await getAuthenticatedHttpClient()\n .get(\n `${getConfig().LMS_BASE_URL}/api/mfe_context`,\n requestConfig,\n )\n .catch((e) => {\n throw (e);\n });\n\n return {\n thirdPartyAuthContext: data.contextData || {},\n };\n}\n\nexport default fetchThirdPartyAuthContext;\n"],"mappings":"AAAA,SAASA,SAAS,QAAQ,wBAAwB;AAClD,SAASC,0BAA0B,QAAQ,6BAA6B;;AAExE;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAeC,0BAA0BA,CAACC,SAAS,EAAE;EACnD,MAAMC,aAAa,GAAG;IACpBC,OAAO,EAAE;MAAE,cAAc,EAAE;IAAoC,CAAC;IAChEC,MAAM,EAAEH,SAAS;IACjBI,QAAQ,EAAE;EACZ,CAAC;EAED,MAAM;IAAEC;EAAK,CAAC,GAAG,MAAMP,0BAA0B,CAAC,CAAC,CAChDQ,GAAG,CACD,GAAET,SAAS,CAAC,CAAC,CAACU,YAAa,kBAAiB,EAC7CN,aACF,CAAC,CACAO,KAAK,CAAEC,CAAC,IAAK;IACZ,MAAOA,CAAC;EACV,CAAC,CAAC;EAEJ,OAAO;IACLC,qBAAqB,EAAEL,IAAI,CAACM,WAAW,IAAI,CAAC;EAC9C,CAAC;AACH;AAEA,eAAeZ,0BAA0B","ignoreList":[]} \ No newline at end of file diff --git a/dist/authn-component/data/utils.js b/dist/authn-component/data/utils.js new file mode 100644 index 00000000..21107589 --- /dev/null +++ b/dist/authn-component/data/utils.js @@ -0,0 +1,19 @@ +import { VALID_AUTH_PARAMS } from '../../data/constants'; + +/** + * Filters context data to include only keys specified in VALID_AUTH_PARAMS. + * + * @param {Object} context - The context object to filter. + * @returns {Object} A new object containing only the filtered key-value pairs. + */ +const validateContextData = context => { + if (context) { + return Object.fromEntries(Object.entries(context).filter(_ref => { + let [key] = _ref; + return VALID_AUTH_PARAMS.includes(key); + })); + } + return context; +}; +export default validateContextData; +//# sourceMappingURL=utils.js.map \ No newline at end of file diff --git a/dist/authn-component/data/utils.js.map b/dist/authn-component/data/utils.js.map new file mode 100644 index 00000000..cc9077fb --- /dev/null +++ b/dist/authn-component/data/utils.js.map @@ -0,0 +1 @@ +{"version":3,"file":"utils.js","names":["VALID_AUTH_PARAMS","validateContextData","context","Object","fromEntries","entries","filter","_ref","key","includes"],"sources":["../../../src/authn-component/data/utils.js"],"sourcesContent":["import { VALID_AUTH_PARAMS } from '../../data/constants';\n\n/**\n * Filters context data to include only keys specified in VALID_AUTH_PARAMS.\n *\n * @param {Object} context - The context object to filter.\n * @returns {Object} A new object containing only the filtered key-value pairs.\n */\nconst validateContextData = (context) => {\n if (context) {\n return Object.fromEntries(\n Object.entries(context).filter(([key]) => VALID_AUTH_PARAMS.includes(key)),\n );\n }\n return context;\n};\n\nexport default validateContextData;\n"],"mappings":"AAAA,SAASA,iBAAiB,QAAQ,sBAAsB;;AAExD;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,mBAAmB,GAAIC,OAAO,IAAK;EACvC,IAAIA,OAAO,EAAE;IACX,OAAOC,MAAM,CAACC,WAAW,CACvBD,MAAM,CAACE,OAAO,CAACH,OAAO,CAAC,CAACI,MAAM,CAACC,IAAA;MAAA,IAAC,CAACC,GAAG,CAAC,GAAAD,IAAA;MAAA,OAAKP,iBAAiB,CAACS,QAAQ,CAACD,GAAG,CAAC;IAAA,EAC3E,CAAC;EACH;EACA,OAAON,OAAO;AAChB,CAAC;AAED,eAAeD,mBAAmB","ignoreList":[]} \ No newline at end of file diff --git a/dist/authn-component/index.js b/dist/authn-component/index.js new file mode 100644 index 00000000..997b4873 --- /dev/null +++ b/dist/authn-component/index.js @@ -0,0 +1,184 @@ +function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } +function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } +function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } +function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); } +function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } +import React, { useEffect, useMemo, useState } from 'react'; +import { Spinner } from '@openedx/paragon'; +import PropTypes from 'prop-types'; +import { getThirdPartyAuthContext, setCurrentOpenedForm, setOnboardingComponentContext } from './data/reducers'; +import validateContextData from './data/utils'; +import BaseContainer from '../base-container'; +import AuthnProvider from '../data/authnProvider'; +import { ENTERPRISE_LOGIN, FORGOT_PASSWORD_FORM, LOGIN_FORM, PENDING_STATE, PROGRESSIVE_PROFILING_FORM, REGISTRATION_FORM, RESET_PASSWORD_FORM, VALID_FORMS } from '../data/constants'; +import { useDispatch, useSelector } from '../data/storeHooks'; +import getAllPossibleQueryParams from '../data/utils'; +import { ForgotPasswordForm, LoginForm, ProgressiveProfilingForm, RegistrationForm, ResetPasswordForm } from '../forms'; +import EnterpriseSSO from '../forms/enterprise-sso-popup'; +import { getTpaHint, getTpaProvider } from '../forms/enterprise-sso-popup/data/utils'; +import { REQUIRE_PASSWORD_CHANGE } from '../forms/login-popup/data/constants'; +import { TOKEN_STATE } from '../forms/reset-password-popup/reset-password/data/constants'; +/** + * Main component that conditionally renders a login or registration form inside a modal window. + * + * @param {boolean} isOpen - Required. Whether the modal window is open. + * @param {function} close - Required. Function to close the modal window. + * @param {string} formToRender - Optional. Indicates which form to render ('login' or 'register'). + * @param {Object} context - Optional. Additional context needed for authentication, such as enrollment data. + * + * @returns {JSX.Element} The rendered component containing the login or registration form. + */ +export const AuthnComponent = _ref => { + let { + isOpen, + close, + context = null, + formToRender + } = _ref; + const dispatch = useDispatch(); + const queryParams = useMemo(() => getAllPossibleQueryParams(), []); + const [screenSize, setScreenSize] = useState('lg'); + const [hasCloseButton, setHasCloseButton] = useState(true); + const currentForm = useSelector(state => state.commonData.currentForm); + const providers = useSelector(state => state.commonData.thirdPartyAuthContext?.providers); + const secondaryProviders = useSelector(state => state.commonData.thirdPartyAuthContext?.secondaryProviders); + const thirdPartyAuthApiStatus = useSelector(state => state.commonData.thirdPartyAuthApiStatus); + const loginErrorCode = useSelector(state => state.login.loginError?.errorCode); + const resetPasswordTokenStatus = useSelector(state => state.resetPassword?.status); + const tpaHint = getTpaHint(); + const { + provider: tpaProvider + } = getTpaProvider(tpaHint, providers, secondaryProviders); + const pendingState = queryParams?.tpa_hint && thirdPartyAuthApiStatus === PENDING_STATE; + useEffect(() => { + if (currentForm === PROGRESSIVE_PROFILING_FORM) { + setHasCloseButton(false); + setScreenSize('fullscreen'); + } + if (loginErrorCode === REQUIRE_PASSWORD_CHANGE && currentForm === FORGOT_PASSWORD_FORM) { + setHasCloseButton(false); + } + if (currentForm === RESET_PASSWORD_FORM && resetPasswordTokenStatus === TOKEN_STATE.PENDING) { + setHasCloseButton(false); + } + if (currentForm === RESET_PASSWORD_FORM && resetPasswordTokenStatus !== TOKEN_STATE.PENDING) { + setHasCloseButton(true); + } + }, [currentForm, resetPasswordTokenStatus, loginErrorCode]); + useEffect(() => { + if (tpaProvider) { + dispatch(setCurrentOpenedForm(ENTERPRISE_LOGIN)); + } + if (!tpaProvider && formToRender) { + dispatch(setCurrentOpenedForm(formToRender)); + } + }, [dispatch, formToRender, tpaProvider, queryParams]); + useEffect(() => { + let validatedContext = {}; + if (context) { + validatedContext = validateContextData(context); + } + dispatch(setOnboardingComponentContext(validatedContext)); + dispatch(getThirdPartyAuthContext(_objectSpread(_objectSpread({}, validatedContext), queryParams))); + }, [context, dispatch, queryParams]); + const getForm = () => { + if (currentForm === ENTERPRISE_LOGIN) { + return /*#__PURE__*/React.createElement(EnterpriseSSO, { + provider: tpaProvider + }); + } + if (currentForm === FORGOT_PASSWORD_FORM) { + return /*#__PURE__*/React.createElement(ForgotPasswordForm, null); + } + if (currentForm === LOGIN_FORM) { + return /*#__PURE__*/React.createElement(LoginForm, null); + } + if (currentForm === PROGRESSIVE_PROFILING_FORM) { + return /*#__PURE__*/React.createElement(ProgressiveProfilingForm, null); + } + if (currentForm === REGISTRATION_FORM) { + return /*#__PURE__*/React.createElement(RegistrationForm, null); + } + if (currentForm === RESET_PASSWORD_FORM) { + return /*#__PURE__*/React.createElement(ResetPasswordForm, null); + } + return null; + }; + const getSpinner = () => /*#__PURE__*/React.createElement("div", { + className: "w-100 text-center p-5", + "data-testid": "tpa-spinner" + }, /*#__PURE__*/React.createElement(Spinner, { + className: "m-5", + animation: "border", + variant: "primary" + })); + return /*#__PURE__*/React.createElement(BaseContainer, { + isOpen: isOpen, + close: close, + hasCloseButton: hasCloseButton, + size: screenSize + }, pendingState ? getSpinner() : getForm()); +}; +AuthnComponent.propTypes = { + isOpen: PropTypes.bool.isRequired, + close: PropTypes.func.isRequired, + context: PropTypes.shape({ + course_id: PropTypes.string, + enrollment_action: PropTypes.string, + email_opt_in: PropTypes.bool + }), + formToRender: PropTypes.oneOf(VALID_FORMS).isRequired +}; + +/** + * Higher Order Component that wraps AuthnComponent with AppProvider. + */ +const AuthnComponentWithProvider = props => { + if (props.isOpen) { + return /*#__PURE__*/React.createElement(AuthnProvider, null, /*#__PURE__*/React.createElement(AuthnComponent, props)); + } + return null; +}; +AuthnComponentWithProvider.propTypes = { + isOpen: PropTypes.bool.isRequired, + close: PropTypes.func.isRequired, + context: PropTypes.shape({ + course_id: PropTypes.string, + enrollment_action: PropTypes.string, + email_opt_in: PropTypes.bool + }), + formToRender: PropTypes.oneOf(VALID_FORMS), + locale: PropTypes.string +}; + +/** + * Component that renders a sign-in form using AuthnComponentWithProvider. + * + * @param {Object} props - Props for the component. + * @returns {JSX.Element} The rendered sign-in component. + */ +export const SignInComponent = props => /*#__PURE__*/React.createElement(AuthnComponentWithProvider, _extends({}, props, { + formToRender: LOGIN_FORM +})); + +/** + * Component that renders a sign-up form using AuthnComponentWithProvider. + * + * @param {Object} props - Props for the component. + * @returns {JSX.Element} The rendered sign-up component. + */ +export const SignUpComponent = props => /*#__PURE__*/React.createElement(AuthnComponentWithProvider, _extends({}, props, { + formToRender: REGISTRATION_FORM +})); + +/** + * Component that renders a reset password form using AuthnComponentWithProvider. + * + * @param {Object} props - Props for the component. + * @returns {JSX.Element} The rendered reset password component. + */ +export const ResetPasswordComponent = props => /*#__PURE__*/React.createElement(AuthnComponentWithProvider, _extends({}, props, { + formToRender: RESET_PASSWORD_FORM +})); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/authn-component/index.js.map b/dist/authn-component/index.js.map new file mode 100644 index 00000000..32243ad5 --- /dev/null +++ b/dist/authn-component/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["React","useEffect","useMemo","useState","Spinner","PropTypes","getThirdPartyAuthContext","setCurrentOpenedForm","setOnboardingComponentContext","validateContextData","BaseContainer","AuthnProvider","ENTERPRISE_LOGIN","FORGOT_PASSWORD_FORM","LOGIN_FORM","PENDING_STATE","PROGRESSIVE_PROFILING_FORM","REGISTRATION_FORM","RESET_PASSWORD_FORM","VALID_FORMS","useDispatch","useSelector","getAllPossibleQueryParams","ForgotPasswordForm","LoginForm","ProgressiveProfilingForm","RegistrationForm","ResetPasswordForm","EnterpriseSSO","getTpaHint","getTpaProvider","REQUIRE_PASSWORD_CHANGE","TOKEN_STATE","AuthnComponent","_ref","isOpen","close","context","formToRender","dispatch","queryParams","screenSize","setScreenSize","hasCloseButton","setHasCloseButton","currentForm","state","commonData","providers","thirdPartyAuthContext","secondaryProviders","thirdPartyAuthApiStatus","loginErrorCode","login","loginError","errorCode","resetPasswordTokenStatus","resetPassword","status","tpaHint","provider","tpaProvider","pendingState","tpa_hint","PENDING","validatedContext","_objectSpread","getForm","createElement","getSpinner","className","animation","variant","size","propTypes","bool","isRequired","func","shape","course_id","string","enrollment_action","email_opt_in","oneOf","AuthnComponentWithProvider","props","locale","SignInComponent","_extends","SignUpComponent","ResetPasswordComponent"],"sources":["../../src/authn-component/index.jsx"],"sourcesContent":["import React, { useEffect, useMemo, useState } from 'react';\n\nimport { Spinner } from '@openedx/paragon';\nimport PropTypes from 'prop-types';\n\nimport { getThirdPartyAuthContext, setCurrentOpenedForm, setOnboardingComponentContext } from './data/reducers';\nimport validateContextData from './data/utils';\nimport BaseContainer from '../base-container';\nimport AuthnProvider from '../data/authnProvider';\nimport {\n ENTERPRISE_LOGIN,\n FORGOT_PASSWORD_FORM,\n LOGIN_FORM,\n PENDING_STATE,\n PROGRESSIVE_PROFILING_FORM,\n REGISTRATION_FORM,\n RESET_PASSWORD_FORM,\n VALID_FORMS,\n} from '../data/constants';\nimport { useDispatch, useSelector } from '../data/storeHooks';\nimport getAllPossibleQueryParams from '../data/utils';\nimport {\n ForgotPasswordForm,\n LoginForm,\n ProgressiveProfilingForm,\n RegistrationForm,\n ResetPasswordForm,\n} from '../forms';\nimport EnterpriseSSO from '../forms/enterprise-sso-popup';\nimport { getTpaHint, getTpaProvider } from '../forms/enterprise-sso-popup/data/utils';\nimport { REQUIRE_PASSWORD_CHANGE } from '../forms/login-popup/data/constants';\nimport { TOKEN_STATE } from '../forms/reset-password-popup/reset-password/data/constants';\n/**\n * Main component that conditionally renders a login or registration form inside a modal window.\n *\n * @param {boolean} isOpen - Required. Whether the modal window is open.\n * @param {function} close - Required. Function to close the modal window.\n * @param {string} formToRender - Optional. Indicates which form to render ('login' or 'register').\n * @param {Object} context - Optional. Additional context needed for authentication, such as enrollment data.\n *\n * @returns {JSX.Element} The rendered component containing the login or registration form.\n */\nexport const AuthnComponent = ({\n isOpen, close, context = null, formToRender,\n}) => {\n const dispatch = useDispatch();\n const queryParams = useMemo(() => getAllPossibleQueryParams(), []);\n\n const [screenSize, setScreenSize] = useState('lg');\n const [hasCloseButton, setHasCloseButton] = useState(true);\n\n const currentForm = useSelector(state => state.commonData.currentForm);\n const providers = useSelector(state => state.commonData.thirdPartyAuthContext?.providers);\n const secondaryProviders = useSelector(state => state.commonData.thirdPartyAuthContext?.secondaryProviders);\n const thirdPartyAuthApiStatus = useSelector(state => state.commonData.thirdPartyAuthApiStatus);\n const loginErrorCode = useSelector(state => state.login.loginError?.errorCode);\n const resetPasswordTokenStatus = useSelector(state => state.resetPassword?.status);\n\n const tpaHint = getTpaHint();\n const { provider: tpaProvider } = getTpaProvider(tpaHint, providers, secondaryProviders);\n const pendingState = queryParams?.tpa_hint && thirdPartyAuthApiStatus === PENDING_STATE;\n\n useEffect(() => {\n if (currentForm === PROGRESSIVE_PROFILING_FORM) {\n setHasCloseButton(false);\n setScreenSize('fullscreen');\n }\n if (loginErrorCode === REQUIRE_PASSWORD_CHANGE\n && currentForm === FORGOT_PASSWORD_FORM\n ) {\n setHasCloseButton(false);\n }\n if (currentForm === RESET_PASSWORD_FORM && resetPasswordTokenStatus === TOKEN_STATE.PENDING) {\n setHasCloseButton(false);\n }\n if (currentForm === RESET_PASSWORD_FORM && resetPasswordTokenStatus !== TOKEN_STATE.PENDING) {\n setHasCloseButton(true);\n }\n }, [currentForm, resetPasswordTokenStatus, loginErrorCode]);\n\n useEffect(() => {\n if (tpaProvider) {\n dispatch(setCurrentOpenedForm(ENTERPRISE_LOGIN));\n }\n if (!tpaProvider && formToRender) {\n dispatch(setCurrentOpenedForm(formToRender));\n }\n }, [dispatch, formToRender, tpaProvider, queryParams]);\n\n useEffect(() => {\n let validatedContext = {};\n if (context) {\n validatedContext = validateContextData(context);\n }\n dispatch(setOnboardingComponentContext(validatedContext));\n dispatch(getThirdPartyAuthContext({ ...validatedContext, ...queryParams }));\n }, [context, dispatch, queryParams]);\n\n const getForm = () => {\n if (currentForm === ENTERPRISE_LOGIN) {\n return ;\n }\n if (currentForm === FORGOT_PASSWORD_FORM) {\n return ;\n }\n if (currentForm === LOGIN_FORM) {\n return ;\n }\n if (currentForm === PROGRESSIVE_PROFILING_FORM) {\n return ;\n }\n if (currentForm === REGISTRATION_FORM) {\n return ;\n }\n if (currentForm === RESET_PASSWORD_FORM) {\n return ;\n }\n return null;\n };\n\n const getSpinner = () => (\n
\n \n
\n );\n\n return (\n \n {pendingState\n ? getSpinner()\n : getForm()}\n \n );\n};\n\nAuthnComponent.propTypes = {\n isOpen: PropTypes.bool.isRequired,\n close: PropTypes.func.isRequired,\n context: PropTypes.shape({\n course_id: PropTypes.string,\n enrollment_action: PropTypes.string,\n email_opt_in: PropTypes.bool,\n }),\n formToRender: PropTypes.oneOf(VALID_FORMS).isRequired,\n};\n\n/**\n * Higher Order Component that wraps AuthnComponent with AppProvider.\n */\nconst AuthnComponentWithProvider = (props) => {\n if (props.isOpen) {\n return (\n \n \n \n );\n }\n\n return null;\n};\n\nAuthnComponentWithProvider.propTypes = {\n isOpen: PropTypes.bool.isRequired,\n close: PropTypes.func.isRequired,\n context: PropTypes.shape({\n course_id: PropTypes.string,\n enrollment_action: PropTypes.string,\n email_opt_in: PropTypes.bool,\n }),\n formToRender: PropTypes.oneOf(VALID_FORMS),\n locale: PropTypes.string,\n};\n\n/**\n * Component that renders a sign-in form using AuthnComponentWithProvider.\n *\n * @param {Object} props - Props for the component.\n * @returns {JSX.Element} The rendered sign-in component.\n */\nexport const SignInComponent = (props) => (\n \n);\n\n/**\n * Component that renders a sign-up form using AuthnComponentWithProvider.\n *\n * @param {Object} props - Props for the component.\n * @returns {JSX.Element} The rendered sign-up component.\n */\nexport const SignUpComponent = (props) => (\n \n);\n\n/**\n * Component that renders a reset password form using AuthnComponentWithProvider.\n *\n * @param {Object} props - Props for the component.\n * @returns {JSX.Element} The rendered reset password component.\n */\nexport const ResetPasswordComponent = (props) => (\n \n);\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/base-container/index.js b/dist/base-container/index.js new file mode 100644 index 00000000..6cd6b523 --- /dev/null +++ b/dist/base-container/index.js @@ -0,0 +1,64 @@ +import React from 'react'; +import { ModalDialog } from '@openedx/paragon'; +import classNames from 'classnames'; +import PropTypes from 'prop-types'; +import { useDispatch } from '../data/storeHooks'; +import { deleteQueryParams } from '../data/utils'; +import { loginErrorClear } from '../forms/login-popup/data/reducers'; +import { clearAllRegistrationErrors } from '../forms/registration-popup/data/reducers'; +import { forgotPasswordClearStatus } from '../forms/reset-password-popup/forgot-password/data/reducers'; +import './index.scss'; + +/** + * Base component for registration or login form modals. + * + * @param {boolean} isOpen - Required. Whether to open the modal window. + * @param {function} close - Required. Is used to the modal window. + * @param {React.node} children - Required. The login or registration form. + * @param {boolean} hasCloseButton - Optional. Denotes whether modal should have close button or not. + * @param {string} size - Optional. Specifies size of modal. + * + * @returns {JSX.Element} The rendered login or registration form modal. + */ +const BaseContainer = _ref => { + let { + children, + close, + hasCloseButton = true, + isOpen, + size = 'lg' + } = _ref; + const dispatch = useDispatch(); + const handleOnClose = () => { + deleteQueryParams(['authMode', 'tpa_hint', 'password_reset_token', 'track']); + dispatch(forgotPasswordClearStatus()); + dispatch(loginErrorClear()); + dispatch(clearAllRegistrationErrors()); + close(); + }; + return /*#__PURE__*/React.createElement(ModalDialog, { + isOpen: isOpen, + onClose: handleOnClose, + size: size, + isBlocking: true, + variant: "default", + title: "authn-component", + className: classNames('bg-light-200 authn-component__modal', { + 'authn-component__modal-full-height': size === 'fullscreen' + }), + hasCloseButton: hasCloseButton + }, /*#__PURE__*/React.createElement(ModalDialog.Body, { + className: "modal-body-container p-0" + }, /*#__PURE__*/React.createElement("div", { + className: "d-flex w-100 h-100 justify-content-center overflow-hidden" + }, children))); +}; +BaseContainer.propTypes = { + children: PropTypes.node.isRequired, + isOpen: PropTypes.bool.isRequired, + close: PropTypes.func.isRequired, + size: PropTypes.string, + hasCloseButton: PropTypes.bool +}; +export default BaseContainer; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/base-container/index.js.map b/dist/base-container/index.js.map new file mode 100644 index 00000000..be354b06 --- /dev/null +++ b/dist/base-container/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["React","ModalDialog","classNames","PropTypes","useDispatch","deleteQueryParams","loginErrorClear","clearAllRegistrationErrors","forgotPasswordClearStatus","BaseContainer","_ref","children","close","hasCloseButton","isOpen","size","dispatch","handleOnClose","createElement","onClose","isBlocking","variant","title","className","Body","propTypes","node","isRequired","bool","func","string"],"sources":["../../src/base-container/index.jsx"],"sourcesContent":["import React from 'react';\n\nimport { ModalDialog } from '@openedx/paragon';\nimport classNames from 'classnames';\nimport PropTypes from 'prop-types';\n\nimport { useDispatch } from '../data/storeHooks';\nimport { deleteQueryParams } from '../data/utils';\nimport { loginErrorClear } from '../forms/login-popup/data/reducers';\nimport { clearAllRegistrationErrors } from '../forms/registration-popup/data/reducers';\nimport { forgotPasswordClearStatus } from '../forms/reset-password-popup/forgot-password/data/reducers';\nimport './index.scss';\n\n/**\n * Base component for registration or login form modals.\n *\n * @param {boolean} isOpen - Required. Whether to open the modal window.\n * @param {function} close - Required. Is used to the modal window.\n * @param {React.node} children - Required. The login or registration form.\n * @param {boolean} hasCloseButton - Optional. Denotes whether modal should have close button or not.\n * @param {string} size - Optional. Specifies size of modal.\n *\n * @returns {JSX.Element} The rendered login or registration form modal.\n */\nconst BaseContainer = ({\n children,\n close,\n hasCloseButton = true,\n isOpen,\n size = 'lg',\n}) => {\n const dispatch = useDispatch();\n\n const handleOnClose = () => {\n deleteQueryParams(['authMode', 'tpa_hint', 'password_reset_token', 'track']);\n dispatch(forgotPasswordClearStatus());\n dispatch(loginErrorClear());\n dispatch(clearAllRegistrationErrors());\n close();\n };\n\n return (\n \n \n
\n {children}\n
\n
\n \n );\n};\n\nBaseContainer.propTypes = {\n children: PropTypes.node.isRequired,\n isOpen: PropTypes.bool.isRequired,\n close: PropTypes.func.isRequired,\n size: PropTypes.string,\n hasCloseButton: PropTypes.bool,\n};\n\nexport default BaseContainer;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AAEzB,SAASC,WAAW,QAAQ,kBAAkB;AAC9C,OAAOC,UAAU,MAAM,YAAY;AACnC,OAAOC,SAAS,MAAM,YAAY;AAElC,SAASC,WAAW,QAAQ,oBAAoB;AAChD,SAASC,iBAAiB,QAAQ,eAAe;AACjD,SAASC,eAAe,QAAQ,oCAAoC;AACpE,SAASC,0BAA0B,QAAQ,2CAA2C;AACtF,SAASC,yBAAyB,QAAQ,6DAA6D;AACvG,OAAO,cAAc;;AAErB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,aAAa,GAAGC,IAAA,IAMhB;EAAA,IANiB;IACrBC,QAAQ;IACRC,KAAK;IACLC,cAAc,GAAG,IAAI;IACrBC,MAAM;IACNC,IAAI,GAAG;EACT,CAAC,GAAAL,IAAA;EACC,MAAMM,QAAQ,GAAGZ,WAAW,CAAC,CAAC;EAE9B,MAAMa,aAAa,GAAGA,CAAA,KAAM;IAC1BZ,iBAAiB,CAAC,CAAC,UAAU,EAAE,UAAU,EAAE,sBAAsB,EAAE,OAAO,CAAC,CAAC;IAC5EW,QAAQ,CAACR,yBAAyB,CAAC,CAAC,CAAC;IACrCQ,QAAQ,CAACV,eAAe,CAAC,CAAC,CAAC;IAC3BU,QAAQ,CAACT,0BAA0B,CAAC,CAAC,CAAC;IACtCK,KAAK,CAAC,CAAC;EACT,CAAC;EAED,oBACEZ,KAAA,CAAAkB,aAAA,CAACjB,WAAW;IACVa,MAAM,EAAEA,MAAO;IACfK,OAAO,EAAEF,aAAc;IACvBF,IAAI,EAAEA,IAAK;IACXK,UAAU;IACVC,OAAO,EAAC,SAAS;IACjBC,KAAK,EAAC,iBAAiB;IACvBC,SAAS,EAAErB,UAAU,CACnB,qCAAqC,EACrC;MACE,oCAAoC,EAAEa,IAAI,KAAK;IACjD,CACF,CAAE;IACFF,cAAc,EAAEA;EAAe,gBAE/Bb,KAAA,CAAAkB,aAAA,CAACjB,WAAW,CAACuB,IAAI;IAACD,SAAS,EAAC;EAA0B,gBACpDvB,KAAA,CAAAkB,aAAA;IAAKK,SAAS,EAAC;EAA2D,GACvEZ,QACE,CACW,CACP,CAAC;AAElB,CAAC;AAEDF,aAAa,CAACgB,SAAS,GAAG;EACxBd,QAAQ,EAAER,SAAS,CAACuB,IAAI,CAACC,UAAU;EACnCb,MAAM,EAAEX,SAAS,CAACyB,IAAI,CAACD,UAAU;EACjCf,KAAK,EAAET,SAAS,CAAC0B,IAAI,CAACF,UAAU;EAChCZ,IAAI,EAAEZ,SAAS,CAAC2B,MAAM;EACtBjB,cAAc,EAAEV,SAAS,CAACyB;AAC5B,CAAC;AAED,eAAenB,aAAa","ignoreList":[]} \ No newline at end of file diff --git a/dist/base-container/index.scss b/dist/base-container/index.scss new file mode 100644 index 00000000..03c92731 --- /dev/null +++ b/dist/base-container/index.scss @@ -0,0 +1,38 @@ +@import "~@edx/brand-edx.org/paragon/variables"; + +.authn-component__modal { + max-height: 98vh !important; +} + +.authn-component__modal-full-height { + max-height: 100vh !important; +} + +@media (max-width: 375px) { + .authn-component__modal { + max-height: 100vh !important; + margin: 0 !important; + } +} + + +.modal-body-container .pgn__modal-body-content { + height: 100% !important; +} + +// This class is related to close button of modal +.authn-component__modal .pgn__modal-close-container .pgn__modal-close-button { + background: $white !important; + border-radius: 50% !important; + color: $light-700 !important; + border: 2px solid $light-500 !important; +} + + +.authn-component__modal .pgn__modal-body { + overflow-x: hidden !important; +} + +.authn-component__modal .pgn__modal-body::after { + display: none !important; +} diff --git a/dist/common-ui/InlineLink/index.js b/dist/common-ui/InlineLink/index.js new file mode 100644 index 00000000..be326461 --- /dev/null +++ b/dist/common-ui/InlineLink/index.js @@ -0,0 +1,57 @@ +import React from 'react'; +import { Hyperlink } from '@openedx/paragon'; +import PropTypes from 'prop-types'; + +/** + * A component that serves two purposes: + * 1. External redirection with `destination`. + * 2. Internal redirection with `onClick`. + * + * When `destination` is provided, clicking the link will navigate to the specified URL. + * If `onClick` is provided, clicking the link will trigger the `onClick` function instead of navigating externally. + * + * @param {string} className - Additional class name for styling. + * @param {string} destination - The URL to redirect to when clicked. Only used if `onClick` is `null`. + * @param {string} linkHelpText - The help text displayed alongside the link. + * @param {string} linkText - The text displayed for the link. + * @param {Function} onClick - The function to call when the link is clicked. If provided, `destination` is ignored. + * @param {boolean} targetBlank - Tells whether to open the link in a new tab or not + */ +const InlineLink = _ref => { + let { + className = '', + destination = '', + linkHelpText = '', + linkText, + onClick = null, + targetBlank = false + } = _ref; + const handleClick = e => { + if (onClick) { + e.preventDefault(); + onClick(); + } + }; + return /*#__PURE__*/React.createElement("div", { + className: `popup-container_inline-link_container ${className}` + }, linkHelpText && /*#__PURE__*/React.createElement("span", { + className: "text-gray-800" + }, linkHelpText), /*#__PURE__*/React.createElement(Hyperlink, { + target: targetBlank ? '_blank' : '_self', + className: "pl-1 popup-container_inline-link_hyperlink", + destination: destination, + onClick: handleClick, + isInline: true, + showLaunchIcon: false + }, linkText)); +}; +InlineLink.propTypes = { + className: PropTypes.string, + destination: PropTypes.string, + onClick: PropTypes.func, + linkHelpText: PropTypes.string, + linkText: PropTypes.string.isRequired, + targetBlank: PropTypes.bool +}; +export default InlineLink; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/common-ui/InlineLink/index.js.map b/dist/common-ui/InlineLink/index.js.map new file mode 100644 index 00000000..56e01e34 --- /dev/null +++ b/dist/common-ui/InlineLink/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["React","Hyperlink","PropTypes","InlineLink","_ref","className","destination","linkHelpText","linkText","onClick","targetBlank","handleClick","e","preventDefault","createElement","target","isInline","showLaunchIcon","propTypes","string","func","isRequired","bool"],"sources":["../../../src/common-ui/InlineLink/index.jsx"],"sourcesContent":["import React from 'react';\n\nimport { Hyperlink } from '@openedx/paragon';\nimport PropTypes from 'prop-types';\n\n/**\n * A component that serves two purposes:\n * 1. External redirection with `destination`.\n * 2. Internal redirection with `onClick`.\n *\n * When `destination` is provided, clicking the link will navigate to the specified URL.\n * If `onClick` is provided, clicking the link will trigger the `onClick` function instead of navigating externally.\n *\n * @param {string} className - Additional class name for styling.\n * @param {string} destination - The URL to redirect to when clicked. Only used if `onClick` is `null`.\n * @param {string} linkHelpText - The help text displayed alongside the link.\n * @param {string} linkText - The text displayed for the link.\n * @param {Function} onClick - The function to call when the link is clicked. If provided, `destination` is ignored.\n * @param {boolean} targetBlank - Tells whether to open the link in a new tab or not\n */\nconst InlineLink = ({\n className = '',\n destination = '',\n linkHelpText = '',\n linkText,\n onClick = null,\n targetBlank = false,\n}) => {\n const handleClick = (e) => {\n if (onClick) {\n e.preventDefault();\n onClick();\n }\n };\n\n return (\n
\n {linkHelpText && (\n \n {linkHelpText}\n \n )}\n \n {linkText}\n \n
\n );\n};\n\nInlineLink.propTypes = {\n className: PropTypes.string,\n destination: PropTypes.string,\n onClick: PropTypes.func,\n linkHelpText: PropTypes.string,\n linkText: PropTypes.string.isRequired,\n targetBlank: PropTypes.bool,\n};\n\nexport default InlineLink;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AAEzB,SAASC,SAAS,QAAQ,kBAAkB;AAC5C,OAAOC,SAAS,MAAM,YAAY;;AAElC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,UAAU,GAAGC,IAAA,IAOb;EAAA,IAPc;IAClBC,SAAS,GAAG,EAAE;IACdC,WAAW,GAAG,EAAE;IAChBC,YAAY,GAAG,EAAE;IACjBC,QAAQ;IACRC,OAAO,GAAG,IAAI;IACdC,WAAW,GAAG;EAChB,CAAC,GAAAN,IAAA;EACC,MAAMO,WAAW,GAAIC,CAAC,IAAK;IACzB,IAAIH,OAAO,EAAE;MACXG,CAAC,CAACC,cAAc,CAAC,CAAC;MAClBJ,OAAO,CAAC,CAAC;IACX;EACF,CAAC;EAED,oBACET,KAAA,CAAAc,aAAA;IAAKT,SAAS,EAAG,yCAAwCA,SAAU;EAAE,GAClEE,YAAY,iBACXP,KAAA,CAAAc,aAAA;IAAMT,SAAS,EAAC;EAAe,GAC5BE,YACG,CACP,eACDP,KAAA,CAAAc,aAAA,CAACb,SAAS;IACRc,MAAM,EAAEL,WAAW,GAAG,QAAQ,GAAG,OAAQ;IACzCL,SAAS,EAAC,4CAA4C;IACtDC,WAAW,EAAEA,WAAY;IACzBG,OAAO,EAAEE,WAAY;IACrBK,QAAQ;IACRC,cAAc,EAAE;EAAM,GAErBT,QACQ,CACR,CAAC;AAEV,CAAC;AAEDL,UAAU,CAACe,SAAS,GAAG;EACrBb,SAAS,EAAEH,SAAS,CAACiB,MAAM;EAC3Bb,WAAW,EAAEJ,SAAS,CAACiB,MAAM;EAC7BV,OAAO,EAAEP,SAAS,CAACkB,IAAI;EACvBb,YAAY,EAAEL,SAAS,CAACiB,MAAM;EAC9BX,QAAQ,EAAEN,SAAS,CAACiB,MAAM,CAACE,UAAU;EACrCX,WAAW,EAAER,SAAS,CAACoB;AACzB,CAAC;AAED,eAAenB,UAAU","ignoreList":[]} \ No newline at end of file diff --git a/dist/common-ui/InlineLink/index.scss b/dist/common-ui/InlineLink/index.scss new file mode 100644 index 00000000..fa1de9a3 --- /dev/null +++ b/dist/common-ui/InlineLink/index.scss @@ -0,0 +1,8 @@ +.popup-container_inline-link_container { + gap: 4px !important; +} + +.popup-container_inline-link_hyperlink { + cursor: pointer !important; + display: inline !important; +} diff --git a/dist/common-ui/SocialAuthButtons/constants.js b/dist/common-ui/SocialAuthButtons/constants.js new file mode 100644 index 00000000..e3d48de9 --- /dev/null +++ b/dist/common-ui/SocialAuthButtons/constants.js @@ -0,0 +1,88 @@ +import React from 'react'; + +/** + * Object containing social media logos as keys and their corresponding SVG images as values. + * Used for displaying social media logos in the UI. + */ +const socialLogos = { + Apple: /*#__PURE__*/React.createElement("svg", { + xmlns: "http://www.w3.org/2000/svg", + width: "24", + height: "24", + viewBox: "0 0 24 24", + fill: "none" + }, /*#__PURE__*/React.createElement("path", { + fill: "white", + d: "M21.2806 18.424C20.9328 19.2275 20.5211 19.9672 20.0441 20.6473C19.3938 21.5743 18.8614 22.216 18.4511 22.5724C17.8151 23.1573 17.1336 23.4569 16.4039 23.4739C15.88 23.4739 15.2483 23.3248 14.5129 23.0224C13.775 22.7214 13.097 22.5724 12.477 22.5724C11.8268 22.5724 11.1294 22.7214 10.3835 23.0224C9.63644 23.3248 9.03463 23.4824 8.5745 23.498C7.87472 23.5278 7.17722 23.2198 6.48099 22.5724C6.03662 22.1848 5.48081 21.5204 4.81496 20.5791C4.10057 19.574 3.51323 18.4084 3.0531 17.0795C2.56032 15.6442 2.31329 14.2543 2.31329 12.9087C2.31329 11.3673 2.64636 10.0379 3.31348 8.92386C3.83778 8.02902 4.53528 7.32314 5.40826 6.80495C6.28124 6.28675 7.2245 6.02269 8.2403 6.00579C8.79611 6.00579 9.52499 6.17772 10.4308 6.51561C11.334 6.85464 11.9139 7.02656 12.1682 7.02656C12.3583 7.02656 13.0026 6.82553 14.0948 6.42475C15.1276 6.05307 15.9993 5.89917 16.7134 5.95979C18.6485 6.11596 20.1023 6.87877 21.0691 8.25305C19.3385 9.30165 18.4824 10.7703 18.4994 12.6544C18.515 14.122 19.0474 15.3432 20.0937 16.3129C20.5679 16.7629 21.0975 17.1108 21.6867 17.3578C21.5589 17.7283 21.424 18.0833 21.2806 18.424ZM16.8426 0.960146C16.8426 2.11041 16.4224 3.1844 15.5847 4.17848C14.5739 5.36025 13.3513 6.04313 12.0254 5.93537C12.0085 5.79738 11.9987 5.65214 11.9987 5.49952C11.9987 4.39527 12.4794 3.21351 13.3331 2.24725C13.7593 1.75802 14.3013 1.35123 14.9586 1.02673C15.6146 0.707068 16.235 0.530288 16.8185 0.500015C16.8355 0.653787 16.8426 0.807569 16.8426 0.960131V0.960146Z" + })), + Facebook: /*#__PURE__*/React.createElement("svg", { + xmlns: "http://www.w3.org/2000/svg", + width: "24", + height: "24", + viewBox: "0 0 24 24", + fill: "none" + }, /*#__PURE__*/React.createElement("g", null, /*#__PURE__*/React.createElement("path", { + fill: "white", + d: "M23.5 12.0698C23.5 5.71857 18.3513 0.569849 12 0.569849C5.64872 0.569849 0.5 5.71857 0.5 12.0698C0.5 17.8098 4.70538 22.5674 10.2031 23.4301V15.3941H7.2832V12.0698H10.2031V9.53626C10.2031 6.65407 11.92 5.06204 14.5468 5.06204C15.805 5.06204 17.1211 5.28665 17.1211 5.28665V8.11672H15.671C14.2424 8.11672 13.7969 9.00319 13.7969 9.91263V12.0698H16.9863L16.4765 15.3941H13.7969V23.4301C19.2946 22.5674 23.5 17.8098 23.5 12.0698Z" + })), /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("clipPath", { + id: "clip0_877_9222" + }, /*#__PURE__*/React.createElement("rect", { + width: "24", + height: "24", + fill: "white" + })))), + Google: /*#__PURE__*/React.createElement("svg", { + width: "24", + height: "24", + version: "1.1", + xmlns: "http://www.w3.org/2000/svg", + viewBox: "0 0 48 48" + }, /*#__PURE__*/React.createElement("path", { + fill: "#EA4335", + d: "M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z" + }), /*#__PURE__*/React.createElement("path", { + fill: "#4285F4", + d: "M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z" + }), /*#__PURE__*/React.createElement("path", { + fill: "#FBBC05", + d: "M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z" + }), /*#__PURE__*/React.createElement("path", { + fill: "#34A853", + d: "M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z" + }), /*#__PURE__*/React.createElement("path", { + fill: "none", + d: "M0 0h48v48H0z" + })), + Microsoft: /*#__PURE__*/React.createElement("svg", { + xmlns: "http://www.w3.org/2000/svg", + width: "24", + height: "24", + viewBox: "0 0 21 21" + }, /*#__PURE__*/React.createElement("rect", { + x: "1", + y: "1", + width: "9", + height: "9", + fill: "#f25022" + }), /*#__PURE__*/React.createElement("rect", { + x: "1", + y: "11", + width: "9", + height: "9", + fill: "#00a4ef" + }), /*#__PURE__*/React.createElement("rect", { + x: "11", + y: "1", + width: "9", + height: "9", + fill: "#7fba00" + }), /*#__PURE__*/React.createElement("rect", { + x: "11", + y: "11", + width: "9", + height: "9", + fill: "#ffb900" + })) +}; +export default socialLogos; +//# sourceMappingURL=constants.js.map \ No newline at end of file diff --git a/dist/common-ui/SocialAuthButtons/constants.js.map b/dist/common-ui/SocialAuthButtons/constants.js.map new file mode 100644 index 00000000..53a1b6e6 --- /dev/null +++ b/dist/common-ui/SocialAuthButtons/constants.js.map @@ -0,0 +1 @@ +{"version":3,"file":"constants.js","names":["React","socialLogos","Apple","createElement","xmlns","width","height","viewBox","fill","d","Facebook","id","Google","version","Microsoft","x","y"],"sources":["../../../src/common-ui/SocialAuthButtons/constants.jsx"],"sourcesContent":["import React from 'react';\n\n/**\n * Object containing social media logos as keys and their corresponding SVG images as values.\n * Used for displaying social media logos in the UI.\n */\nconst socialLogos = {\n Apple: (\n \n \n \n ),\n Facebook: (\n \n \n \n \n \n \n \n \n \n \n ),\n Google: (\n \n \n \n \n \n \n \n ),\n Microsoft: (\n \n \n \n \n \n \n ),\n};\n\nexport default socialLogos;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;;AAEzB;AACA;AACA;AACA;AACA,MAAMC,WAAW,GAAG;EAClBC,KAAK,eACHF,KAAA,CAAAG,aAAA;IAAKC,KAAK,EAAC,4BAA4B;IAACC,KAAK,EAAC,IAAI;IAACC,MAAM,EAAC,IAAI;IAACC,OAAO,EAAC,WAAW;IAACC,IAAI,EAAC;EAAM,gBAC5FR,KAAA,CAAAG,aAAA;IAAMK,IAAI,EAAC,OAAO;IAACC,CAAC,EAAC;EAAg8C,CAAE,CACp9C,CACN;EACDC,QAAQ,eACNV,KAAA,CAAAG,aAAA;IAAKC,KAAK,EAAC,4BAA4B;IAACC,KAAK,EAAC,IAAI;IAACC,MAAM,EAAC,IAAI;IAACC,OAAO,EAAC,WAAW;IAACC,IAAI,EAAC;EAAM,gBAC5FR,KAAA,CAAAG,aAAA,yBACEH,KAAA,CAAAG,aAAA;IAAMK,IAAI,EAAC,OAAO;IAACC,CAAC,EAAC;EAA4a,CAAE,CAClc,CAAC,eACJT,KAAA,CAAAG,aAAA,4BACEH,KAAA,CAAAG,aAAA;IAAUQ,EAAE,EAAC;EAAgB,gBAC3BX,KAAA,CAAAG,aAAA;IAAME,KAAK,EAAC,IAAI;IAACC,MAAM,EAAC,IAAI;IAACE,IAAI,EAAC;EAAO,CAAE,CACnC,CACN,CACH,CACN;EACDI,MAAM,eACJZ,KAAA,CAAAG,aAAA;IAAKE,KAAK,EAAC,IAAI;IAACC,MAAM,EAAC,IAAI;IAACO,OAAO,EAAC,KAAK;IAACT,KAAK,EAAC,4BAA4B;IAACG,OAAO,EAAC;EAAW,gBAC9FP,KAAA,CAAAG,aAAA;IAAMK,IAAI,EAAC,SAAS;IAACC,CAAC,EAAC;EAAyI,CAAE,CAAC,eACnKT,KAAA,CAAAG,aAAA;IAAMK,IAAI,EAAC,SAAS;IAACC,CAAC,EAAC;EAA2H,CAAE,CAAC,eACrJT,KAAA,CAAAG,aAAA;IAAMK,IAAI,EAAC,SAAS;IAACC,CAAC,EAAC;EAAkI,CAAE,CAAC,eAC5JT,KAAA,CAAAG,aAAA;IAAMK,IAAI,EAAC,SAAS;IAACC,CAAC,EAAC;EAA6I,CAAE,CAAC,eACvKT,KAAA,CAAAG,aAAA;IAAMK,IAAI,EAAC,MAAM;IAACC,CAAC,EAAC;EAAe,CAAE,CAClC,CACN;EACDK,SAAS,eACPd,KAAA,CAAAG,aAAA;IAAKC,KAAK,EAAC,4BAA4B;IAACC,KAAK,EAAC,IAAI;IAACC,MAAM,EAAC,IAAI;IAACC,OAAO,EAAC;EAAW,gBAChFP,KAAA,CAAAG,aAAA;IAAMY,CAAC,EAAC,GAAG;IAACC,CAAC,EAAC,GAAG;IAACX,KAAK,EAAC,GAAG;IAACC,MAAM,EAAC,GAAG;IAACE,IAAI,EAAC;EAAS,CAAE,CAAC,eACxDR,KAAA,CAAAG,aAAA;IAAMY,CAAC,EAAC,GAAG;IAACC,CAAC,EAAC,IAAI;IAACX,KAAK,EAAC,GAAG;IAACC,MAAM,EAAC,GAAG;IAACE,IAAI,EAAC;EAAS,CAAE,CAAC,eACzDR,KAAA,CAAAG,aAAA;IAAMY,CAAC,EAAC,IAAI;IAACC,CAAC,EAAC,GAAG;IAACX,KAAK,EAAC,GAAG;IAACC,MAAM,EAAC,GAAG;IAACE,IAAI,EAAC;EAAS,CAAE,CAAC,eACzDR,KAAA,CAAAG,aAAA;IAAMY,CAAC,EAAC,IAAI;IAACC,CAAC,EAAC,IAAI;IAACX,KAAK,EAAC,GAAG;IAACC,MAAM,EAAC,GAAG;IAACE,IAAI,EAAC;EAAS,CAAE,CACtD;AAET,CAAC;AAED,eAAeP,WAAW","ignoreList":[]} \ No newline at end of file diff --git a/dist/common-ui/SocialAuthButtons/index.js b/dist/common-ui/SocialAuthButtons/index.js new file mode 100644 index 00000000..2e604839 --- /dev/null +++ b/dist/common-ui/SocialAuthButtons/index.js @@ -0,0 +1,122 @@ +import React, { forwardRef } from 'react'; +import { getConfig } from '@edx/frontend-platform'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Button, Skeleton } from '@openedx/paragon'; +import classNames from 'classnames'; +import PropTypes from 'prop-types'; +import socialLogos from './constants'; +import providersSelector from '../../authn-component/data/selectors'; +import { PENDING_STATE } from '../../data/constants'; +import { useSelector } from '../../data/storeHooks'; +import messages from '../messages'; +import './index.scss'; + +/** + * A reusable button component for social authentication providers (Facebook, Google, etc.). + * + * @param {object} provider - Required. The social authentication provider + * @param {boolean} isLoginForm - Whether to display a sign-in or sign-up text based on the login page context. + * @param {boolean} inverseTextColor - Whether to use inverted text color (white for dark backgrounds). + * + * @returns {JSX.Element} The rendered SocialAuthButton component. + */ +export const SocialAuthButton = /*#__PURE__*/forwardRef((_ref, ref) => { + let { + provider = null, + isLoginForm, + inverseTextColor = false + } = _ref; + const { + formatMessage + } = useIntl(); + const registrationFields = useSelector(state => state.register.registrationFields); + if (!provider) { + return null; + } + const { + id: providerId, + name: providerName, + loginUrl, + registerUrl + } = provider; + const handleSubmit = e => { + e.preventDefault(); + + // setting marketingEmailsOptIn state in local storage to preserve user marketing opt-in + // choice in case of SSO auto registratioon + localStorage.setItem('marketingEmailsOptIn', registrationFields?.marketingEmailsOptIn); + const url = e.currentTarget.dataset.providerUrl; + window.location.href = getConfig().LMS_BASE_URL + url; + }; + return /*#__PURE__*/React.createElement(Button, { + ref: ref, + id: providerId, + type: "button", + "data-provider-url": isLoginForm ? loginUrl : registerUrl, + onClick: handleSubmit, + className: classNames(`social-auth-button_${providerName.toLowerCase()} d-flex justify-content-start mb-3 + authn-sso-btn__pill-shaped`, { + 'text-white': inverseTextColor, + 'text-black-50': !inverseTextColor + }), + variant: "tertiary" + }, socialLogos[providerName], /*#__PURE__*/React.createElement("span", null, isLoginForm ? formatMessage(messages.socialAuthProviderSigninTitle, { + providerName + }) : formatMessage(messages.socialAuthProviderSignupTitle, { + providerName + }))); +}); +SocialAuthButton.propTypes = { + provider: PropTypes.shape({ + id: PropTypes.string, + name: PropTypes.string, + loginUrl: PropTypes.string, + registerUrl: PropTypes.string + }), + isLoginForm: PropTypes.bool.isRequired, + inverseTextColor: PropTypes.bool +}; + +/** + * A component that renders a group of SocialAuthButton components for different social authentication providers. + * + * @param {boolean} isLoginForm - Whether the component is used on a login page. Affects the displayed text. + * + * @returns {JSX.Element} The rendered SocialAuthProviders component. + */ +const SocialAuthProviders = /*#__PURE__*/forwardRef((_ref2, ref) => { + let { + isLoginForm = true + } = _ref2; + const thirdPartyAuthApiStatus = useSelector(state => state.commonData.thirdPartyAuthApiStatus); + const providers = useSelector(providersSelector); + if (thirdPartyAuthApiStatus === PENDING_STATE) { + return /*#__PURE__*/React.createElement(Skeleton, { + height: 44, + count: 4 + }); + } + return /*#__PURE__*/React.createElement("div", { + className: "d-flex flex-column" + }, /*#__PURE__*/React.createElement(SocialAuthButton, { + isLoginForm: isLoginForm, + provider: providers?.Google, + ref: ref + }), /*#__PURE__*/React.createElement(SocialAuthButton, { + isLoginForm: isLoginForm, + provider: providers?.Apple, + inverseTextColor: true + }), /*#__PURE__*/React.createElement(SocialAuthButton, { + isLoginForm: isLoginForm, + provider: providers?.Facebook, + inverseTextColor: true + }), /*#__PURE__*/React.createElement(SocialAuthButton, { + isLoginForm: isLoginForm, + provider: providers?.Microsoft + })); +}); +SocialAuthProviders.propTypes = { + isLoginForm: PropTypes.bool +}; +export default SocialAuthProviders; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/common-ui/SocialAuthButtons/index.js.map b/dist/common-ui/SocialAuthButtons/index.js.map new file mode 100644 index 00000000..41b5f5b0 --- /dev/null +++ b/dist/common-ui/SocialAuthButtons/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["React","forwardRef","getConfig","useIntl","Button","Skeleton","classNames","PropTypes","socialLogos","providersSelector","PENDING_STATE","useSelector","messages","SocialAuthButton","_ref","ref","provider","isLoginForm","inverseTextColor","formatMessage","registrationFields","state","register","id","providerId","name","providerName","loginUrl","registerUrl","handleSubmit","e","preventDefault","localStorage","setItem","marketingEmailsOptIn","url","currentTarget","dataset","providerUrl","window","location","href","LMS_BASE_URL","createElement","type","onClick","className","toLowerCase","variant","socialAuthProviderSigninTitle","socialAuthProviderSignupTitle","propTypes","shape","string","bool","isRequired","SocialAuthProviders","_ref2","thirdPartyAuthApiStatus","commonData","providers","height","count","Google","Apple","Facebook","Microsoft"],"sources":["../../../src/common-ui/SocialAuthButtons/index.jsx"],"sourcesContent":["import React, { forwardRef } from 'react';\n\nimport { getConfig } from '@edx/frontend-platform';\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport { Button, Skeleton } from '@openedx/paragon';\nimport classNames from 'classnames';\nimport PropTypes from 'prop-types';\n\nimport socialLogos from './constants';\nimport providersSelector from '../../authn-component/data/selectors';\nimport { PENDING_STATE } from '../../data/constants';\nimport { useSelector } from '../../data/storeHooks';\nimport messages from '../messages';\n\nimport './index.scss';\n\n/**\n * A reusable button component for social authentication providers (Facebook, Google, etc.).\n *\n * @param {object} provider - Required. The social authentication provider\n * @param {boolean} isLoginForm - Whether to display a sign-in or sign-up text based on the login page context.\n * @param {boolean} inverseTextColor - Whether to use inverted text color (white for dark backgrounds).\n *\n * @returns {JSX.Element} The rendered SocialAuthButton component.\n */\nexport const SocialAuthButton = forwardRef(({\n provider = null,\n isLoginForm,\n inverseTextColor = false,\n}, ref) => {\n const { formatMessage } = useIntl();\n\n const registrationFields = useSelector(state => state.register.registrationFields);\n\n if (!provider) {\n return null;\n }\n\n const {\n id: providerId,\n name: providerName,\n loginUrl,\n registerUrl,\n } = provider;\n\n const handleSubmit = (e) => {\n e.preventDefault();\n\n // setting marketingEmailsOptIn state in local storage to preserve user marketing opt-in\n // choice in case of SSO auto registratioon\n localStorage.setItem('marketingEmailsOptIn', registrationFields?.marketingEmailsOptIn);\n const url = e.currentTarget.dataset.providerUrl;\n window.location.href = getConfig().LMS_BASE_URL + url;\n };\n\n return (\n \n {socialLogos[providerName]}\n \n {\n isLoginForm\n ? formatMessage(messages.socialAuthProviderSigninTitle, { providerName })\n : formatMessage(messages.socialAuthProviderSignupTitle, { providerName })\n }\n \n \n );\n});\n\nSocialAuthButton.propTypes = {\n provider: PropTypes.shape({\n id: PropTypes.string,\n name: PropTypes.string,\n loginUrl: PropTypes.string,\n registerUrl: PropTypes.string,\n }),\n isLoginForm: PropTypes.bool.isRequired,\n inverseTextColor: PropTypes.bool,\n};\n\n/**\n * A component that renders a group of SocialAuthButton components for different social authentication providers.\n *\n * @param {boolean} isLoginForm - Whether the component is used on a login page. Affects the displayed text.\n *\n * @returns {JSX.Element} The rendered SocialAuthProviders component.\n */\nconst SocialAuthProviders = forwardRef(({ isLoginForm = true }, ref) => {\n const thirdPartyAuthApiStatus = useSelector(state => state.commonData.thirdPartyAuthApiStatus);\n const providers = useSelector(providersSelector);\n\n if (thirdPartyAuthApiStatus === PENDING_STATE) {\n return (\n \n );\n }\n return (\n
\n \n \n \n \n
\n );\n});\n\nSocialAuthProviders.propTypes = {\n isLoginForm: PropTypes.bool,\n};\n\nexport default SocialAuthProviders;\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/common-ui/SocialAuthButtons/index.scss b/dist/common-ui/SocialAuthButtons/index.scss new file mode 100644 index 00000000..8007f198 --- /dev/null +++ b/dist/common-ui/SocialAuthButtons/index.scss @@ -0,0 +1,46 @@ +@import "~@edx/brand-edx.org/paragon/variables"; + +$facebook-blue: #1877F2; +$icon-and-text-gap: 15px; + +.authn-component__modal .social-auth-button_facebook { + gap: $icon-and-text-gap !important; + background-color: $facebook-blue !important; + + &.btn-tertiary:hover { + background-color: $facebook-blue !important; + } +} + +.authn-component__modal .social-auth-button_google { + gap: $icon-and-text-gap !important; + margin-top: 0 !important; + background-color: $white !important; +} + +.authn-component__modal .social-auth-button_apple { + gap: $icon-and-text-gap !important; + background-color: $black !important; + + &.btn-tertiary:hover { + background-color: $black !important; + } +} + +.authn-component__modal .social-auth-button_microsoft { + margin-bottom: 0 !important; + gap: $icon-and-text-gap !important; + background-color: $white !important; + + &.btn-tertiary:hover { + background-color: $white !important; + } +} + +.authn-component__modal .react-loading-skeleton:nth-last-child(n+3) { + margin-bottom: 16px !important; +} + +.authn-component__modal .react-loading-skeleton { + line-height: 44px !important; +} diff --git a/dist/common-ui/index.js b/dist/common-ui/index.js new file mode 100644 index 00000000..b62fa30c --- /dev/null +++ b/dist/common-ui/index.js @@ -0,0 +1,3 @@ +export { default as InlineLink } from './InlineLink'; +export { default as SocialAuthProviders, SocialAuthButton } from './SocialAuthButtons'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/common-ui/index.js.map b/dist/common-ui/index.js.map new file mode 100644 index 00000000..45e603f9 --- /dev/null +++ b/dist/common-ui/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["default","InlineLink","SocialAuthProviders","SocialAuthButton"],"sources":["../../src/common-ui/index.js"],"sourcesContent":["export { default as InlineLink } from './InlineLink';\nexport { default as SocialAuthProviders, SocialAuthButton } from './SocialAuthButtons';\n"],"mappings":"AAAA,SAASA,OAAO,IAAIC,UAAU,QAAQ,cAAc;AACpD,SAASD,OAAO,IAAIE,mBAAmB,EAAEC,gBAAgB,QAAQ,qBAAqB","ignoreList":[]} \ No newline at end of file diff --git a/dist/common-ui/index.scss b/dist/common-ui/index.scss new file mode 100644 index 00000000..3e05abc2 --- /dev/null +++ b/dist/common-ui/index.scss @@ -0,0 +1,2 @@ +@import "InlineLink"; +@import "SocialAuthButtons"; diff --git a/dist/common-ui/messages.js b/dist/common-ui/messages.js new file mode 100644 index 00000000..f36aed2e --- /dev/null +++ b/dist/common-ui/messages.js @@ -0,0 +1,15 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; +const messages = defineMessages({ + socialAuthProviderSignupTitle: { + id: 'social.auth.provide.signup.title', + defaultMessage: 'Sign up with {providerName}', + description: 'Title that appears on the social sign up buttons i.e Sign up with Google' + }, + socialAuthProviderSigninTitle: { + id: 'social.auth.provide.signin.title', + defaultMessage: 'Sign in with {providerName}', + description: 'Title that appears on the social sign in buttons i.e Sign in with Google' + } +}); +export default messages; +//# sourceMappingURL=messages.js.map \ No newline at end of file diff --git a/dist/common-ui/messages.js.map b/dist/common-ui/messages.js.map new file mode 100644 index 00000000..858b5647 --- /dev/null +++ b/dist/common-ui/messages.js.map @@ -0,0 +1 @@ +{"version":3,"file":"messages.js","names":["defineMessages","messages","socialAuthProviderSignupTitle","id","defaultMessage","description","socialAuthProviderSigninTitle"],"sources":["../../src/common-ui/messages.js"],"sourcesContent":["import { defineMessages } from '@edx/frontend-platform/i18n';\n\nconst messages = defineMessages({\n socialAuthProviderSignupTitle: {\n id: 'social.auth.provide.signup.title',\n defaultMessage: 'Sign up with {providerName}',\n description: 'Title that appears on the social sign up buttons i.e Sign up with Google',\n },\n socialAuthProviderSigninTitle: {\n id: 'social.auth.provide.signin.title',\n defaultMessage: 'Sign in with {providerName}',\n description: 'Title that appears on the social sign in buttons i.e Sign in with Google',\n },\n});\n\nexport default messages;\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,6BAA6B;AAE5D,MAAMC,QAAQ,GAAGD,cAAc,CAAC;EAC9BE,6BAA6B,EAAE;IAC7BC,EAAE,EAAE,kCAAkC;IACtCC,cAAc,EAAE,6BAA6B;IAC7CC,WAAW,EAAE;EACf,CAAC;EACDC,6BAA6B,EAAE;IAC7BH,EAAE,EAAE,kCAAkC;IACtCC,cAAc,EAAE,6BAA6B;IAC7CC,WAAW,EAAE;EACf;AACF,CAAC,CAAC;AAEF,eAAeJ,QAAQ","ignoreList":[]} \ No newline at end of file diff --git a/dist/config/index.js b/dist/config/index.js new file mode 100644 index 00000000..ffdf4c2d --- /dev/null +++ b/dist/config/index.js @@ -0,0 +1,2 @@ + +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/config/index.js.map b/dist/config/index.js.map new file mode 100644 index 00000000..e5aaf901 --- /dev/null +++ b/dist/config/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":[],"sources":["../../src/config/index.js"],"sourcesContent":[""],"mappings":"","ignoreList":[]} \ No newline at end of file diff --git a/dist/data/authnProvider.js b/dist/data/authnProvider.js new file mode 100644 index 00000000..8476b0c3 --- /dev/null +++ b/dist/data/authnProvider.js @@ -0,0 +1,21 @@ +import React from 'react'; +import { Provider } from 'react-redux'; +import { getLocale, getMessages, IntlProvider } from '@edx/frontend-platform/i18n'; +import store from './configureStore'; +import { AuthnContext } from './storeHooks'; + +// eslint-disable-next-line react/prop-types +const AuthnProvider = _ref => { + let { + children + } = _ref; + return /*#__PURE__*/React.createElement(IntlProvider, { + locale: getLocale(), + messages: getMessages() + }, /*#__PURE__*/React.createElement(Provider, { + context: AuthnContext, + store: store + }, children)); +}; +export default AuthnProvider; +//# sourceMappingURL=authnProvider.js.map \ No newline at end of file diff --git a/dist/data/authnProvider.js.map b/dist/data/authnProvider.js.map new file mode 100644 index 00000000..9cefab9c --- /dev/null +++ b/dist/data/authnProvider.js.map @@ -0,0 +1 @@ +{"version":3,"file":"authnProvider.js","names":["React","Provider","getLocale","getMessages","IntlProvider","store","AuthnContext","AuthnProvider","_ref","children","createElement","locale","messages","context"],"sources":["../../src/data/authnProvider.jsx"],"sourcesContent":["import React from 'react';\nimport { Provider } from 'react-redux';\n\nimport { getLocale, getMessages, IntlProvider } from '@edx/frontend-platform/i18n';\n\nimport store from './configureStore';\nimport { AuthnContext } from './storeHooks';\n\n// eslint-disable-next-line react/prop-types\nconst AuthnProvider = ({ children }) => (\n \n \n {children}\n \n \n);\n\nexport default AuthnProvider;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,QAAQ,QAAQ,aAAa;AAEtC,SAASC,SAAS,EAAEC,WAAW,EAAEC,YAAY,QAAQ,6BAA6B;AAElF,OAAOC,KAAK,MAAM,kBAAkB;AACpC,SAASC,YAAY,QAAQ,cAAc;;AAE3C;AACA,MAAMC,aAAa,GAAGC,IAAA;EAAA,IAAC;IAAEC;EAAS,CAAC,GAAAD,IAAA;EAAA,oBACjCR,KAAA,CAAAU,aAAA,CAACN,YAAY;IAACO,MAAM,EAAET,SAAS,CAAC,CAAE;IAACU,QAAQ,EAAET,WAAW,CAAC;EAAE,gBACzDH,KAAA,CAAAU,aAAA,CAACT,QAAQ;IAACY,OAAO,EAAEP,YAAa;IAACD,KAAK,EAAEA;EAAM,GAC3CI,QACO,CACE,CAAC;AAAA,CAChB;AAED,eAAeF,aAAa","ignoreList":[]} \ No newline at end of file diff --git a/dist/data/configureStore.js b/dist/data/configureStore.js new file mode 100644 index 00000000..40dbc308 --- /dev/null +++ b/dist/data/configureStore.js @@ -0,0 +1,26 @@ +import { getConfig } from '@edx/frontend-platform'; +import { composeWithDevTools } from '@redux-devtools/extension'; +import { applyMiddleware, compose, createStore } from 'redux'; +import { createLogger } from 'redux-logger'; +import createSagaMiddleware from 'redux-saga'; +import thunkMiddleware from 'redux-thunk'; +import createRootReducer from './reducers'; +import rootSaga from './sagas'; +const sagaMiddleware = createSagaMiddleware(); +function composeMiddleware() { + if (getConfig().ENVIRONMENT === 'development') { + const loggerMiddleware = createLogger({ + collapsed: true + }); + return composeWithDevTools(applyMiddleware(thunkMiddleware, sagaMiddleware, loggerMiddleware)); + } + return compose(applyMiddleware(thunkMiddleware, sagaMiddleware)); +} +function configureStore() { + let initialState = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + const store = createStore(createRootReducer(), initialState, composeMiddleware()); + sagaMiddleware.run(rootSaga); + return store; +} +export default configureStore(); +//# sourceMappingURL=configureStore.js.map \ No newline at end of file diff --git a/dist/data/configureStore.js.map b/dist/data/configureStore.js.map new file mode 100644 index 00000000..d87af95e --- /dev/null +++ b/dist/data/configureStore.js.map @@ -0,0 +1 @@ +{"version":3,"file":"configureStore.js","names":["getConfig","composeWithDevTools","applyMiddleware","compose","createStore","createLogger","createSagaMiddleware","thunkMiddleware","createRootReducer","rootSaga","sagaMiddleware","composeMiddleware","ENVIRONMENT","loggerMiddleware","collapsed","configureStore","initialState","arguments","length","undefined","store","run"],"sources":["../../src/data/configureStore.js"],"sourcesContent":["import { getConfig } from '@edx/frontend-platform';\nimport { composeWithDevTools } from '@redux-devtools/extension';\nimport { applyMiddleware, compose, createStore } from 'redux';\nimport { createLogger } from 'redux-logger';\nimport createSagaMiddleware from 'redux-saga';\nimport thunkMiddleware from 'redux-thunk';\n\nimport createRootReducer from './reducers';\nimport rootSaga from './sagas';\n\nconst sagaMiddleware = createSagaMiddleware();\n\nfunction composeMiddleware() {\n if (getConfig().ENVIRONMENT === 'development') {\n const loggerMiddleware = createLogger({\n collapsed: true,\n });\n return composeWithDevTools(applyMiddleware(thunkMiddleware, sagaMiddleware, loggerMiddleware));\n }\n\n return compose(applyMiddleware(thunkMiddleware, sagaMiddleware));\n}\n\nfunction configureStore(initialState = {}) {\n const store = createStore(\n createRootReducer(),\n initialState,\n composeMiddleware(),\n );\n sagaMiddleware.run(rootSaga);\n\n return store;\n}\n\nexport default configureStore();\n"],"mappings":"AAAA,SAASA,SAAS,QAAQ,wBAAwB;AAClD,SAASC,mBAAmB,QAAQ,2BAA2B;AAC/D,SAASC,eAAe,EAAEC,OAAO,EAAEC,WAAW,QAAQ,OAAO;AAC7D,SAASC,YAAY,QAAQ,cAAc;AAC3C,OAAOC,oBAAoB,MAAM,YAAY;AAC7C,OAAOC,eAAe,MAAM,aAAa;AAEzC,OAAOC,iBAAiB,MAAM,YAAY;AAC1C,OAAOC,QAAQ,MAAM,SAAS;AAE9B,MAAMC,cAAc,GAAGJ,oBAAoB,CAAC,CAAC;AAE7C,SAASK,iBAAiBA,CAAA,EAAG;EAC3B,IAAIX,SAAS,CAAC,CAAC,CAACY,WAAW,KAAK,aAAa,EAAE;IAC7C,MAAMC,gBAAgB,GAAGR,YAAY,CAAC;MACpCS,SAAS,EAAE;IACb,CAAC,CAAC;IACF,OAAOb,mBAAmB,CAACC,eAAe,CAACK,eAAe,EAAEG,cAAc,EAAEG,gBAAgB,CAAC,CAAC;EAChG;EAEA,OAAOV,OAAO,CAACD,eAAe,CAACK,eAAe,EAAEG,cAAc,CAAC,CAAC;AAClE;AAEA,SAASK,cAAcA,CAAA,EAAoB;EAAA,IAAnBC,YAAY,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,CAAC,CAAC;EACvC,MAAMG,KAAK,GAAGhB,WAAW,CACvBI,iBAAiB,CAAC,CAAC,EACnBQ,YAAY,EACZL,iBAAiB,CAAC,CACpB,CAAC;EACDD,cAAc,CAACW,GAAG,CAACZ,QAAQ,CAAC;EAE5B,OAAOW,KAAK;AACd;AAEA,eAAeL,cAAc,CAAC,CAAC","ignoreList":[]} \ No newline at end of file diff --git a/dist/data/constants.js b/dist/data/constants.js new file mode 100644 index 00000000..3a57d9e4 --- /dev/null +++ b/dist/data/constants.js @@ -0,0 +1,34 @@ +// Forms +export const LOGIN_FORM = 'login'; +export const REGISTRATION_FORM = 'registration'; +export const FORGOT_PASSWORD_FORM = 'forgot-password'; +export const RESET_PASSWORD_FORM = 'reset-password'; +export const PROGRESSIVE_PROFILING_FORM = 'progressive-profiling'; +export const ENTERPRISE_LOGIN = 'enterprise-login'; +export const VALID_FORMS = [LOGIN_FORM, REGISTRATION_FORM, RESET_PASSWORD_FORM]; + +// Common States +export const DEFAULT_STATE = 'default'; +export const PENDING_STATE = 'pending'; +export const COMPLETE_STATE = 'complete'; +export const FAILURE_STATE = 'failure'; +export const FORBIDDEN_STATE = 'forbidden'; + +// Error Codes +export const INTERNAL_SERVER_ERROR = 'internal-server-error'; +export const FORBIDDEN_REQUEST = 'forbidden-request'; +export const FORM_SUBMISSION_ERROR = 'form-submission-error'; +export const INVALID_FORM = 'invalid-form'; +export const TPA_AUTHENTICATION_FAILURE = 'tpa-authentication-failure'; +export const TPA_SESSION_EXPIRED = 'tpa-session-expired'; + +// URL Paths +export const ENTERPRISE_LOGIN_URL = '/enterprise/login'; + +// Query string parameters that can be passed to LMS to manage +// things like auto-enrollment upon login and registration. +export const VALID_AUTH_PARAMS = ['course_id', 'enrollment_action', 'course_mode', 'email_opt_in', 'purchase_workflow', 'next', 'tpa_hint', 'account_activation_status', 'authMode', 'password_reset_token']; + +// Regular expression for validating email addresses. +export const VALID_EMAIL_REGEX = '(^[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+(\\.[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+)*' + '|^"([\\001-\\010\\013\\014\\016-\\037!#-\\[\\]-\\177]|\\\\[\\001-\\011\\013\\014\\016-\\177])*"' + ')@((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\\.)+)(?:[A-Z0-9-]{2,63})' + '|\\[(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\]$'; +//# sourceMappingURL=constants.js.map \ No newline at end of file diff --git a/dist/data/constants.js.map b/dist/data/constants.js.map new file mode 100644 index 00000000..19882b45 --- /dev/null +++ b/dist/data/constants.js.map @@ -0,0 +1 @@ +{"version":3,"file":"constants.js","names":["LOGIN_FORM","REGISTRATION_FORM","FORGOT_PASSWORD_FORM","RESET_PASSWORD_FORM","PROGRESSIVE_PROFILING_FORM","ENTERPRISE_LOGIN","VALID_FORMS","DEFAULT_STATE","PENDING_STATE","COMPLETE_STATE","FAILURE_STATE","FORBIDDEN_STATE","INTERNAL_SERVER_ERROR","FORBIDDEN_REQUEST","FORM_SUBMISSION_ERROR","INVALID_FORM","TPA_AUTHENTICATION_FAILURE","TPA_SESSION_EXPIRED","ENTERPRISE_LOGIN_URL","VALID_AUTH_PARAMS","VALID_EMAIL_REGEX"],"sources":["../../src/data/constants.js"],"sourcesContent":["// Forms\nexport const LOGIN_FORM = 'login';\nexport const REGISTRATION_FORM = 'registration';\nexport const FORGOT_PASSWORD_FORM = 'forgot-password';\nexport const RESET_PASSWORD_FORM = 'reset-password';\nexport const PROGRESSIVE_PROFILING_FORM = 'progressive-profiling';\nexport const ENTERPRISE_LOGIN = 'enterprise-login';\nexport const VALID_FORMS = [LOGIN_FORM, REGISTRATION_FORM, RESET_PASSWORD_FORM];\n\n// Common States\nexport const DEFAULT_STATE = 'default';\nexport const PENDING_STATE = 'pending';\nexport const COMPLETE_STATE = 'complete';\nexport const FAILURE_STATE = 'failure';\nexport const FORBIDDEN_STATE = 'forbidden';\n\n// Error Codes\nexport const INTERNAL_SERVER_ERROR = 'internal-server-error';\nexport const FORBIDDEN_REQUEST = 'forbidden-request';\nexport const FORM_SUBMISSION_ERROR = 'form-submission-error';\nexport const INVALID_FORM = 'invalid-form';\nexport const TPA_AUTHENTICATION_FAILURE = 'tpa-authentication-failure';\nexport const TPA_SESSION_EXPIRED = 'tpa-session-expired';\n\n// URL Paths\nexport const ENTERPRISE_LOGIN_URL = '/enterprise/login';\n\n// Query string parameters that can be passed to LMS to manage\n// things like auto-enrollment upon login and registration.\nexport const VALID_AUTH_PARAMS = [\n 'course_id', 'enrollment_action', 'course_mode', 'email_opt_in', 'purchase_workflow',\n 'next', 'tpa_hint', 'account_activation_status', 'authMode', 'password_reset_token',\n];\n\n// Regular expression for validating email addresses.\nexport const VALID_EMAIL_REGEX = '(^[-!#$%&\\'*+/=?^_`{}|~0-9A-Z]+(\\\\.[-!#$%&\\'*+/=?^_`{}|~0-9A-Z]+)*'\n + '|^\"([\\\\001-\\\\010\\\\013\\\\014\\\\016-\\\\037!#-\\\\[\\\\]-\\\\177]|\\\\\\\\[\\\\001-\\\\011\\\\013\\\\014\\\\016-\\\\177])*\"'\n + ')@((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\\\\.)+)(?:[A-Z0-9-]{2,63})'\n + '|\\\\[(25[0-5]|2[0-4]\\\\d|[0-1]?\\\\d?\\\\d)(\\\\.(25[0-5]|2[0-4]\\\\d|[0-1]?\\\\d?\\\\d)){3}\\\\]$';\n"],"mappings":"AAAA;AACA,OAAO,MAAMA,UAAU,GAAG,OAAO;AACjC,OAAO,MAAMC,iBAAiB,GAAG,cAAc;AAC/C,OAAO,MAAMC,oBAAoB,GAAG,iBAAiB;AACrD,OAAO,MAAMC,mBAAmB,GAAG,gBAAgB;AACnD,OAAO,MAAMC,0BAA0B,GAAG,uBAAuB;AACjE,OAAO,MAAMC,gBAAgB,GAAG,kBAAkB;AAClD,OAAO,MAAMC,WAAW,GAAG,CAACN,UAAU,EAAEC,iBAAiB,EAAEE,mBAAmB,CAAC;;AAE/E;AACA,OAAO,MAAMI,aAAa,GAAG,SAAS;AACtC,OAAO,MAAMC,aAAa,GAAG,SAAS;AACtC,OAAO,MAAMC,cAAc,GAAG,UAAU;AACxC,OAAO,MAAMC,aAAa,GAAG,SAAS;AACtC,OAAO,MAAMC,eAAe,GAAG,WAAW;;AAE1C;AACA,OAAO,MAAMC,qBAAqB,GAAG,uBAAuB;AAC5D,OAAO,MAAMC,iBAAiB,GAAG,mBAAmB;AACpD,OAAO,MAAMC,qBAAqB,GAAG,uBAAuB;AAC5D,OAAO,MAAMC,YAAY,GAAG,cAAc;AAC1C,OAAO,MAAMC,0BAA0B,GAAG,4BAA4B;AACtE,OAAO,MAAMC,mBAAmB,GAAG,qBAAqB;;AAExD;AACA,OAAO,MAAMC,oBAAoB,GAAG,mBAAmB;;AAEvD;AACA;AACA,OAAO,MAAMC,iBAAiB,GAAG,CAC/B,WAAW,EAAE,mBAAmB,EAAE,aAAa,EAAE,cAAc,EAAE,mBAAmB,EACpF,MAAM,EAAE,UAAU,EAAE,2BAA2B,EAAE,UAAU,EAAE,sBAAsB,CACpF;;AAED;AACA,OAAO,MAAMC,iBAAiB,GAAG,oEAAoE,GAClE,iGAAiG,GACjG,qEAAqE,GACrE,oFAAoF","ignoreList":[]} \ No newline at end of file diff --git a/dist/data/reducers.js b/dist/data/reducers.js new file mode 100644 index 00000000..ef5213bd --- /dev/null +++ b/dist/data/reducers.js @@ -0,0 +1,13 @@ +import { combineReducers } from 'redux'; +import commonDataReducer, { commonDataStoreName } from '../authn-component/data/reducers'; +import { forgotPasswordReducer, forgotPasswordStoreName, loginReducer, loginStoreName, progressiveProfilingReducer, progressiveProfilingStoreName, registerReducer, registerStoreName, resetPasswordReducer, resetPasswordStoreName } from '../forms'; +const createRootReducer = () => combineReducers({ + [registerStoreName]: registerReducer, + [loginStoreName]: loginReducer, + [progressiveProfilingStoreName]: progressiveProfilingReducer, + [commonDataStoreName]: commonDataReducer, + [forgotPasswordStoreName]: forgotPasswordReducer, + [resetPasswordStoreName]: resetPasswordReducer +}); +export default createRootReducer; +//# sourceMappingURL=reducers.js.map \ No newline at end of file diff --git a/dist/data/reducers.js.map b/dist/data/reducers.js.map new file mode 100644 index 00000000..c611733c --- /dev/null +++ b/dist/data/reducers.js.map @@ -0,0 +1 @@ +{"version":3,"file":"reducers.js","names":["combineReducers","commonDataReducer","commonDataStoreName","forgotPasswordReducer","forgotPasswordStoreName","loginReducer","loginStoreName","progressiveProfilingReducer","progressiveProfilingStoreName","registerReducer","registerStoreName","resetPasswordReducer","resetPasswordStoreName","createRootReducer"],"sources":["../../src/data/reducers.js"],"sourcesContent":["import { combineReducers } from 'redux';\n\nimport commonDataReducer, { commonDataStoreName } from '../authn-component/data/reducers';\nimport {\n forgotPasswordReducer,\n forgotPasswordStoreName,\n loginReducer,\n loginStoreName,\n progressiveProfilingReducer,\n progressiveProfilingStoreName,\n registerReducer,\n registerStoreName,\n resetPasswordReducer,\n resetPasswordStoreName,\n} from '../forms';\n\nconst createRootReducer = () => combineReducers({\n [registerStoreName]: registerReducer,\n [loginStoreName]: loginReducer,\n [progressiveProfilingStoreName]: progressiveProfilingReducer,\n [commonDataStoreName]: commonDataReducer,\n [forgotPasswordStoreName]: forgotPasswordReducer,\n [resetPasswordStoreName]: resetPasswordReducer,\n});\n\nexport default createRootReducer;\n"],"mappings":"AAAA,SAASA,eAAe,QAAQ,OAAO;AAEvC,OAAOC,iBAAiB,IAAIC,mBAAmB,QAAQ,kCAAkC;AACzF,SACEC,qBAAqB,EACrBC,uBAAuB,EACvBC,YAAY,EACZC,cAAc,EACdC,2BAA2B,EAC3BC,6BAA6B,EAC7BC,eAAe,EACfC,iBAAiB,EACjBC,oBAAoB,EACpBC,sBAAsB,QACjB,UAAU;AAEjB,MAAMC,iBAAiB,GAAGA,CAAA,KAAMb,eAAe,CAAC;EAC9C,CAACU,iBAAiB,GAAGD,eAAe;EACpC,CAACH,cAAc,GAAGD,YAAY;EAC9B,CAACG,6BAA6B,GAAGD,2BAA2B;EAC5D,CAACL,mBAAmB,GAAGD,iBAAiB;EACxC,CAACG,uBAAuB,GAAGD,qBAAqB;EAChD,CAACS,sBAAsB,GAAGD;AAC5B,CAAC,CAAC;AAEF,eAAeE,iBAAiB","ignoreList":[]} \ No newline at end of file diff --git a/dist/data/sagas.js b/dist/data/sagas.js new file mode 100644 index 00000000..a4822aad --- /dev/null +++ b/dist/data/sagas.js @@ -0,0 +1,7 @@ +import { all } from 'redux-saga/effects'; +import thirdPartyAuthSaga from '../authn-component/data/sagas'; +import { forgotPasswordSaga, loginSaga, progressiveProfilingSaga, registerSaga, resetPasswordSaga } from '../forms'; +export default function* rootSaga() { + yield all([registerSaga(), progressiveProfilingSaga(), loginSaga(), thirdPartyAuthSaga(), forgotPasswordSaga(), resetPasswordSaga()]); +} +//# sourceMappingURL=sagas.js.map \ No newline at end of file diff --git a/dist/data/sagas.js.map b/dist/data/sagas.js.map new file mode 100644 index 00000000..0a124ce2 --- /dev/null +++ b/dist/data/sagas.js.map @@ -0,0 +1 @@ +{"version":3,"file":"sagas.js","names":["all","thirdPartyAuthSaga","forgotPasswordSaga","loginSaga","progressiveProfilingSaga","registerSaga","resetPasswordSaga","rootSaga"],"sources":["../../src/data/sagas.js"],"sourcesContent":["import { all } from 'redux-saga/effects';\n\nimport thirdPartyAuthSaga from '../authn-component/data/sagas';\nimport {\n forgotPasswordSaga,\n loginSaga,\n progressiveProfilingSaga,\n registerSaga,\n resetPasswordSaga,\n} from '../forms';\n\nexport default function* rootSaga() {\n yield all([\n registerSaga(),\n progressiveProfilingSaga(),\n loginSaga(),\n thirdPartyAuthSaga(),\n forgotPasswordSaga(),\n resetPasswordSaga(),\n ]);\n}\n"],"mappings":"AAAA,SAASA,GAAG,QAAQ,oBAAoB;AAExC,OAAOC,kBAAkB,MAAM,+BAA+B;AAC9D,SACEC,kBAAkB,EAClBC,SAAS,EACTC,wBAAwB,EACxBC,YAAY,EACZC,iBAAiB,QACZ,UAAU;AAEjB,eAAe,UAAUC,QAAQA,CAAA,EAAG;EAClC,MAAMP,GAAG,CAAC,CACRK,YAAY,CAAC,CAAC,EACdD,wBAAwB,CAAC,CAAC,EAC1BD,SAAS,CAAC,CAAC,EACXF,kBAAkB,CAAC,CAAC,EACpBC,kBAAkB,CAAC,CAAC,EACpBI,iBAAiB,CAAC,CAAC,CACpB,CAAC;AACJ","ignoreList":[]} \ No newline at end of file diff --git a/dist/data/segment/utils.js b/dist/data/segment/utils.js new file mode 100644 index 00000000..eef66756 --- /dev/null +++ b/dist/data/segment/utils.js @@ -0,0 +1,44 @@ +function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } +function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } +function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); } +function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } +/* eslint-disable import/prefer-default-export */ +import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics'; +export const LINK_TIMEOUT = 300; + +/** + * Creates an event tracker function that sends a tracking event with the given name and options. + * + * @param {string} name - The name of the event to be tracked. + * @param {object} [options={}] - Additional options to be included with the event. + * @returns {function} - A function that, when called, sends the tracking event. + */ +export const createEventTracker = function (name) { + let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + return () => sendTrackEvent(name, _objectSpread(_objectSpread({}, options), {}, { + app_name: 'onboarding_component' + })); +}; + +/** + * Creates an event tracker function that sends a tracking event with the given name and options. + * + * @param {string} name - The name of the event to be tracked. + * @param {object} [options={}] - Additional options to be included with the event. + * @returns {function} - A function that, when called, sends the tracking event. + */ +export const createPageEventTracker = function (name) { + let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + return () => sendPageEvent(name, options, { + app_name: 'onboarding_component' + }); +}; +export const createLinkTracker = (tracker, href) => e => { + e.preventDefault(); + tracker(); + return setTimeout(() => { + window.location.href = href; + }, LINK_TIMEOUT); +}; +//# sourceMappingURL=utils.js.map \ No newline at end of file diff --git a/dist/data/segment/utils.js.map b/dist/data/segment/utils.js.map new file mode 100644 index 00000000..049f7c35 --- /dev/null +++ b/dist/data/segment/utils.js.map @@ -0,0 +1 @@ +{"version":3,"file":"utils.js","names":["sendPageEvent","sendTrackEvent","LINK_TIMEOUT","createEventTracker","name","options","arguments","length","undefined","_objectSpread","app_name","createPageEventTracker","createLinkTracker","tracker","href","e","preventDefault","setTimeout","window","location"],"sources":["../../../src/data/segment/utils.js"],"sourcesContent":["/* eslint-disable import/prefer-default-export */\nimport { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';\n\nexport const LINK_TIMEOUT = 300;\n\n/**\n * Creates an event tracker function that sends a tracking event with the given name and options.\n *\n * @param {string} name - The name of the event to be tracked.\n * @param {object} [options={}] - Additional options to be included with the event.\n * @returns {function} - A function that, when called, sends the tracking event.\n */\nexport const createEventTracker = (name, options = {}) => () => sendTrackEvent(\n name,\n { ...options, app_name: 'onboarding_component' },\n);\n\n/**\n * Creates an event tracker function that sends a tracking event with the given name and options.\n *\n * @param {string} name - The name of the event to be tracked.\n * @param {object} [options={}] - Additional options to be included with the event.\n * @returns {function} - A function that, when called, sends the tracking event.\n */\nexport const createPageEventTracker = (name, options = null) => () => sendPageEvent(\n name,\n options,\n { app_name: 'onboarding_component' },\n);\n\nexport const createLinkTracker = (tracker, href) => (e) => {\n e.preventDefault();\n tracker();\n return setTimeout(() => { window.location.href = href; }, LINK_TIMEOUT);\n};\n"],"mappings":";;;;;AAAA;AACA,SAASA,aAAa,EAAEC,cAAc,QAAQ,kCAAkC;AAEhF,OAAO,MAAMC,YAAY,GAAG,GAAG;;AAE/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,kBAAkB,GAAG,SAAAA,CAACC,IAAI;EAAA,IAAEC,OAAO,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,CAAC,CAAC;EAAA,OAAK,MAAML,cAAc,CAC5EG,IAAI,EAAAK,aAAA,CAAAA,aAAA,KACCJ,OAAO;IAAEK,QAAQ,EAAE;EAAsB,EAChD,CAAC;AAAA;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,sBAAsB,GAAG,SAAAA,CAACP,IAAI;EAAA,IAAEC,OAAO,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,IAAI;EAAA,OAAK,MAAMN,aAAa,CACjFI,IAAI,EACJC,OAAO,EACP;IAAEK,QAAQ,EAAE;EAAuB,CACrC,CAAC;AAAA;AAED,OAAO,MAAME,iBAAiB,GAAGA,CAACC,OAAO,EAAEC,IAAI,KAAMC,CAAC,IAAK;EACzDA,CAAC,CAACC,cAAc,CAAC,CAAC;EAClBH,OAAO,CAAC,CAAC;EACT,OAAOI,UAAU,CAAC,MAAM;IAAEC,MAAM,CAACC,QAAQ,CAACL,IAAI,GAAGA,IAAI;EAAE,CAAC,EAAEZ,YAAY,CAAC;AACzE,CAAC","ignoreList":[]} \ No newline at end of file diff --git a/dist/data/storeHooks.js b/dist/data/storeHooks.js new file mode 100644 index 00000000..cfd7246c --- /dev/null +++ b/dist/data/storeHooks.js @@ -0,0 +1,9 @@ +import { createContext } from 'react'; +import { createDispatchHook, createSelectorHook } from 'react-redux'; + +// Doing this to avoid colliding the component redux store with host MFE's redux store. +// Reference: https://react-redux.js.org/api/hooks#custom-context +export const AuthnContext = /*#__PURE__*/createContext(null); +export const useDispatch = createDispatchHook(AuthnContext); +export const useSelector = createSelectorHook(AuthnContext); +//# sourceMappingURL=storeHooks.js.map \ No newline at end of file diff --git a/dist/data/storeHooks.js.map b/dist/data/storeHooks.js.map new file mode 100644 index 00000000..cabefa92 --- /dev/null +++ b/dist/data/storeHooks.js.map @@ -0,0 +1 @@ +{"version":3,"file":"storeHooks.js","names":["createContext","createDispatchHook","createSelectorHook","AuthnContext","useDispatch","useSelector"],"sources":["../../src/data/storeHooks.jsx"],"sourcesContent":["import { createContext } from 'react';\nimport {\n createDispatchHook, createSelectorHook,\n} from 'react-redux';\n\n// Doing this to avoid colliding the component redux store with host MFE's redux store.\n// Reference: https://react-redux.js.org/api/hooks#custom-context\nexport const AuthnContext = createContext(null);\n\nexport const useDispatch = createDispatchHook(AuthnContext);\nexport const useSelector = createSelectorHook(AuthnContext);\n"],"mappings":"AAAA,SAASA,aAAa,QAAQ,OAAO;AACrC,SACEC,kBAAkB,EAAEC,kBAAkB,QACjC,aAAa;;AAEpB;AACA;AACA,OAAO,MAAMC,YAAY,gBAAGH,aAAa,CAAC,IAAI,CAAC;AAE/C,OAAO,MAAMI,WAAW,GAAGH,kBAAkB,CAACE,YAAY,CAAC;AAC3D,OAAO,MAAME,WAAW,GAAGH,kBAAkB,CAACC,YAAY,CAAC","ignoreList":[]} \ No newline at end of file diff --git a/dist/data/utils.js b/dist/data/utils.js new file mode 100644 index 00000000..78c31725 --- /dev/null +++ b/dist/data/utils.js @@ -0,0 +1,62 @@ +// Utility functions +import { getConfig } from '@edx/frontend-platform'; +import QueryString from 'query-string'; +import Cookies from 'universal-cookie'; +import { VALID_AUTH_PARAMS } from './constants'; + +/** + * Parses query parameters from a URL string or the current window's location and + * filters out parameters that are not in the VALID_AUTH_PARAMS list. + * + * @param {string|null} locationURl - Optional. The URL string to parse query parameters from. + * If not provided, the function uses the current window's location. + * @returns {Object} An object containing only the valid query parameters. + */ +const getAllPossibleQueryParams = function () { + let locationURl = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + const urlParams = locationURl ? QueryString.parseUrl(locationURl).query : QueryString.parse(window.location.search); + return Object.fromEntries(Object.entries(urlParams).filter(_ref => { + let [key] = _ref; + return VALID_AUTH_PARAMS.includes(key); + })); +}; +export const deleteQueryParams = params => { + const queryParams = getAllPossibleQueryParams(); + const url = new URL(window.location.href); + params.forEach(param => { + if (queryParams[param]) { + url.searchParams.delete(param); + } + }); + window.history.replaceState(window.history.state, '', url.href); +}; +export const setCookie = (cookieName, cookieValue, cookieExpiry) => { + if (cookieName) { + // To avoid setting getting exception when setting cookie with undefined names. + const cookies = new Cookies(); + const options = { + domain: getConfig().SESSION_COOKIE_DOMAIN, + path: '/' + }; + if (cookieExpiry) { + options.expires = cookieExpiry; + } + cookies.set(cookieName, cookieValue, options); + } +}; +export const getCountryCookieValue = () => { + const cookieName = `${getConfig().ONBOARDING_COMPONENT_ENV}-edx-cf-loc`; + const cookies = new Cookies(); + return cookies.get(cookieName); +}; +export const moveScrollToTop = function (ref) { + let block = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'start'; + if (ref?.current?.scrollIntoView) { + ref.current.scrollIntoView({ + behavior: 'smooth', + block + }); + } +}; +export default getAllPossibleQueryParams; +//# sourceMappingURL=utils.js.map \ No newline at end of file diff --git a/dist/data/utils.js.map b/dist/data/utils.js.map new file mode 100644 index 00000000..c0883a94 --- /dev/null +++ b/dist/data/utils.js.map @@ -0,0 +1 @@ +{"version":3,"file":"utils.js","names":["getConfig","QueryString","Cookies","VALID_AUTH_PARAMS","getAllPossibleQueryParams","locationURl","arguments","length","undefined","urlParams","parseUrl","query","parse","window","location","search","Object","fromEntries","entries","filter","_ref","key","includes","deleteQueryParams","params","queryParams","url","URL","href","forEach","param","searchParams","delete","history","replaceState","state","setCookie","cookieName","cookieValue","cookieExpiry","cookies","options","domain","SESSION_COOKIE_DOMAIN","path","expires","set","getCountryCookieValue","ONBOARDING_COMPONENT_ENV","get","moveScrollToTop","ref","block","current","scrollIntoView","behavior"],"sources":["../../src/data/utils.js"],"sourcesContent":["// Utility functions\nimport { getConfig } from '@edx/frontend-platform';\nimport QueryString from 'query-string';\nimport Cookies from 'universal-cookie';\n\nimport { VALID_AUTH_PARAMS } from './constants';\n\n/**\n * Parses query parameters from a URL string or the current window's location and\n * filters out parameters that are not in the VALID_AUTH_PARAMS list.\n *\n * @param {string|null} locationURl - Optional. The URL string to parse query parameters from.\n * If not provided, the function uses the current window's location.\n * @returns {Object} An object containing only the valid query parameters.\n */\nconst getAllPossibleQueryParams = (locationURl = null) => {\n const urlParams = locationURl\n ? QueryString.parseUrl(locationURl).query\n : QueryString.parse(window.location.search);\n\n return Object.fromEntries(\n Object.entries(urlParams).filter(([key]) => VALID_AUTH_PARAMS.includes(key)),\n );\n};\n\nexport const deleteQueryParams = (params) => {\n const queryParams = getAllPossibleQueryParams();\n const url = new URL(window.location.href);\n\n params.forEach((param) => {\n if (queryParams[param]) {\n url.searchParams.delete(param);\n }\n });\n\n window.history.replaceState(window.history.state, '', url.href);\n};\n\nexport const setCookie = (cookieName, cookieValue, cookieExpiry) => {\n if (cookieName) { // To avoid setting getting exception when setting cookie with undefined names.\n const cookies = new Cookies();\n const options = { domain: getConfig().SESSION_COOKIE_DOMAIN, path: '/' };\n if (cookieExpiry) {\n options.expires = cookieExpiry;\n }\n cookies.set(cookieName, cookieValue, options);\n }\n};\n\nexport const getCountryCookieValue = () => {\n const cookieName = `${getConfig().ONBOARDING_COMPONENT_ENV}-edx-cf-loc`;\n const cookies = new Cookies();\n return cookies.get(cookieName);\n};\n\nexport const moveScrollToTop = (ref, block = 'start') => {\n if (ref?.current?.scrollIntoView) {\n ref.current.scrollIntoView({ behavior: 'smooth', block });\n }\n};\n\nexport default getAllPossibleQueryParams;\n"],"mappings":"AAAA;AACA,SAASA,SAAS,QAAQ,wBAAwB;AAClD,OAAOC,WAAW,MAAM,cAAc;AACtC,OAAOC,OAAO,MAAM,kBAAkB;AAEtC,SAASC,iBAAiB,QAAQ,aAAa;;AAE/C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,yBAAyB,GAAG,SAAAA,CAAA,EAAwB;EAAA,IAAvBC,WAAW,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,IAAI;EACnD,MAAMG,SAAS,GAAGJ,WAAW,GACzBJ,WAAW,CAACS,QAAQ,CAACL,WAAW,CAAC,CAACM,KAAK,GACvCV,WAAW,CAACW,KAAK,CAACC,MAAM,CAACC,QAAQ,CAACC,MAAM,CAAC;EAE7C,OAAOC,MAAM,CAACC,WAAW,CACvBD,MAAM,CAACE,OAAO,CAACT,SAAS,CAAC,CAACU,MAAM,CAACC,IAAA;IAAA,IAAC,CAACC,GAAG,CAAC,GAAAD,IAAA;IAAA,OAAKjB,iBAAiB,CAACmB,QAAQ,CAACD,GAAG,CAAC;EAAA,EAC7E,CAAC;AACH,CAAC;AAED,OAAO,MAAME,iBAAiB,GAAIC,MAAM,IAAK;EAC3C,MAAMC,WAAW,GAAGrB,yBAAyB,CAAC,CAAC;EAC/C,MAAMsB,GAAG,GAAG,IAAIC,GAAG,CAACd,MAAM,CAACC,QAAQ,CAACc,IAAI,CAAC;EAEzCJ,MAAM,CAACK,OAAO,CAAEC,KAAK,IAAK;IACxB,IAAIL,WAAW,CAACK,KAAK,CAAC,EAAE;MACtBJ,GAAG,CAACK,YAAY,CAACC,MAAM,CAACF,KAAK,CAAC;IAChC;EACF,CAAC,CAAC;EAEFjB,MAAM,CAACoB,OAAO,CAACC,YAAY,CAACrB,MAAM,CAACoB,OAAO,CAACE,KAAK,EAAE,EAAE,EAAET,GAAG,CAACE,IAAI,CAAC;AACjE,CAAC;AAED,OAAO,MAAMQ,SAAS,GAAGA,CAACC,UAAU,EAAEC,WAAW,EAAEC,YAAY,KAAK;EAClE,IAAIF,UAAU,EAAE;IAAE;IAChB,MAAMG,OAAO,GAAG,IAAItC,OAAO,CAAC,CAAC;IAC7B,MAAMuC,OAAO,GAAG;MAAEC,MAAM,EAAE1C,SAAS,CAAC,CAAC,CAAC2C,qBAAqB;MAAEC,IAAI,EAAE;IAAI,CAAC;IACxE,IAAIL,YAAY,EAAE;MAChBE,OAAO,CAACI,OAAO,GAAGN,YAAY;IAChC;IACAC,OAAO,CAACM,GAAG,CAACT,UAAU,EAAEC,WAAW,EAAEG,OAAO,CAAC;EAC/C;AACF,CAAC;AAED,OAAO,MAAMM,qBAAqB,GAAGA,CAAA,KAAM;EACzC,MAAMV,UAAU,GAAI,GAAErC,SAAS,CAAC,CAAC,CAACgD,wBAAyB,aAAY;EACvE,MAAMR,OAAO,GAAG,IAAItC,OAAO,CAAC,CAAC;EAC7B,OAAOsC,OAAO,CAACS,GAAG,CAACZ,UAAU,CAAC;AAChC,CAAC;AAED,OAAO,MAAMa,eAAe,GAAG,SAAAA,CAACC,GAAG,EAAsB;EAAA,IAApBC,KAAK,GAAA9C,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,OAAO;EAClD,IAAI6C,GAAG,EAAEE,OAAO,EAAEC,cAAc,EAAE;IAChCH,GAAG,CAACE,OAAO,CAACC,cAAc,CAAC;MAAEC,QAAQ,EAAE,QAAQ;MAAEH;IAAM,CAAC,CAAC;EAC3D;AACF,CAAC;AAED,eAAehD,yBAAyB","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/common-components/AuthenticatedRedirection.js b/dist/forms/common-components/AuthenticatedRedirection.js new file mode 100644 index 00000000..1e17e949 --- /dev/null +++ b/dist/forms/common-components/AuthenticatedRedirection.js @@ -0,0 +1,73 @@ +import { getConfig } from '@edx/frontend-platform'; +import PropTypes from 'prop-types'; +import { setCurrentOpenedForm } from '../../authn-component/data/reducers'; +import { PROGRESSIVE_PROFILING_FORM } from '../../data/constants'; +import { LINK_TIMEOUT } from '../../data/segment/utils'; +import { useDispatch } from '../../data/storeHooks'; +import { setCookie } from '../../data/utils'; +import { setProgressiveProfilingRedirectUrl } from '../progressive-profiling-popup/data/reducers'; + +/** + * Component that handles redirection after successful authentication. + * + * Redirections: + * - Redirects to progressive profiling form if redirectToProgressiveProfilingForm is true. + * - Redirects to the finishAuthUrl if provided and not already included in redirectUrl, + * otherwise redirects to the specified redirectUrl. + * + * @param {string} finishAuthUrl - The URL to complete the authentication pipeline. + * @param {string} redirectUrl - The URL to redirect to after authentication. + * @param {boolean} redirectToProgressiveProfilingForm - Flag indicating if to redirect to progressive profiling. + * @param {boolean} success - Flag indicating if authentication was successful. + * + * @returns {null} This component does not render anything, it handles redirects. + */ +const AuthenticatedRedirection = _ref => { + let { + finishAuthUrl = null, + redirectUrl = '', + redirectToProgressiveProfilingForm = false, + success = false, + isLinkTracked = false + } = _ref; + const dispatch = useDispatch(); + if (success) { + let finalRedirectUrl = ''; + + // If we're in a third party auth pipeline, we must complete the pipeline + // once user has successfully logged in. Otherwise, redirect to the specified redirect url. + // Note: For multiple enterprise use case, we need to make sure that user first visits the + // enterprise selection page and then complete the auth workflow + if (finishAuthUrl && !redirectUrl.includes(finishAuthUrl)) { + finalRedirectUrl = getConfig().LMS_BASE_URL + finishAuthUrl; + } else { + finalRedirectUrl = redirectUrl; + } + + // Redirect to Progressive Profiling after successful registration + if (redirectToProgressiveProfilingForm) { + // TODO: Do we still need this cookie? + setCookie('van-504-returning-user', true); + dispatch(setProgressiveProfilingRedirectUrl(finalRedirectUrl)); + dispatch(setCurrentOpenedForm(PROGRESSIVE_PROFILING_FORM)); + return null; + } + if (isLinkTracked) { + setTimeout(() => { + window.location.href = finalRedirectUrl; + }, LINK_TIMEOUT); + } else { + window.location.href = finalRedirectUrl; + } + } + return null; +}; +AuthenticatedRedirection.propTypes = { + finishAuthUrl: PropTypes.string, + success: PropTypes.bool, + redirectUrl: PropTypes.string, + redirectToProgressiveProfilingForm: PropTypes.bool, + isLinkTracked: PropTypes.bool +}; +export default AuthenticatedRedirection; +//# sourceMappingURL=AuthenticatedRedirection.js.map \ No newline at end of file diff --git a/dist/forms/common-components/AuthenticatedRedirection.js.map b/dist/forms/common-components/AuthenticatedRedirection.js.map new file mode 100644 index 00000000..8f0b4719 --- /dev/null +++ b/dist/forms/common-components/AuthenticatedRedirection.js.map @@ -0,0 +1 @@ +{"version":3,"file":"AuthenticatedRedirection.js","names":["getConfig","PropTypes","setCurrentOpenedForm","PROGRESSIVE_PROFILING_FORM","LINK_TIMEOUT","useDispatch","setCookie","setProgressiveProfilingRedirectUrl","AuthenticatedRedirection","_ref","finishAuthUrl","redirectUrl","redirectToProgressiveProfilingForm","success","isLinkTracked","dispatch","finalRedirectUrl","includes","LMS_BASE_URL","setTimeout","window","location","href","propTypes","string","bool"],"sources":["../../../src/forms/common-components/AuthenticatedRedirection.jsx"],"sourcesContent":["import { getConfig } from '@edx/frontend-platform';\nimport PropTypes from 'prop-types';\n\nimport { setCurrentOpenedForm } from '../../authn-component/data/reducers';\nimport { PROGRESSIVE_PROFILING_FORM } from '../../data/constants';\nimport { LINK_TIMEOUT } from '../../data/segment/utils';\nimport { useDispatch } from '../../data/storeHooks';\nimport { setCookie } from '../../data/utils';\nimport {\n setProgressiveProfilingRedirectUrl,\n} from '../progressive-profiling-popup/data/reducers';\n\n/**\n * Component that handles redirection after successful authentication.\n *\n * Redirections:\n * - Redirects to progressive profiling form if redirectToProgressiveProfilingForm is true.\n * - Redirects to the finishAuthUrl if provided and not already included in redirectUrl,\n * otherwise redirects to the specified redirectUrl.\n *\n * @param {string} finishAuthUrl - The URL to complete the authentication pipeline.\n * @param {string} redirectUrl - The URL to redirect to after authentication.\n * @param {boolean} redirectToProgressiveProfilingForm - Flag indicating if to redirect to progressive profiling.\n * @param {boolean} success - Flag indicating if authentication was successful.\n *\n * @returns {null} This component does not render anything, it handles redirects.\n */\nconst AuthenticatedRedirection = ({\n finishAuthUrl = null,\n redirectUrl = '',\n redirectToProgressiveProfilingForm = false,\n success = false,\n isLinkTracked = false,\n}) => {\n const dispatch = useDispatch();\n\n if (success) {\n let finalRedirectUrl = '';\n\n // If we're in a third party auth pipeline, we must complete the pipeline\n // once user has successfully logged in. Otherwise, redirect to the specified redirect url.\n // Note: For multiple enterprise use case, we need to make sure that user first visits the\n // enterprise selection page and then complete the auth workflow\n if (finishAuthUrl && !redirectUrl.includes(finishAuthUrl)) {\n finalRedirectUrl = getConfig().LMS_BASE_URL + finishAuthUrl;\n } else {\n finalRedirectUrl = redirectUrl;\n }\n\n // Redirect to Progressive Profiling after successful registration\n if (redirectToProgressiveProfilingForm) {\n // TODO: Do we still need this cookie?\n setCookie('van-504-returning-user', true);\n\n dispatch(setProgressiveProfilingRedirectUrl(finalRedirectUrl));\n dispatch(setCurrentOpenedForm(PROGRESSIVE_PROFILING_FORM));\n return null;\n }\n\n if (isLinkTracked) {\n setTimeout(() => { window.location.href = finalRedirectUrl; }, LINK_TIMEOUT);\n } else {\n window.location.href = finalRedirectUrl;\n }\n }\n\n return null;\n};\n\nAuthenticatedRedirection.propTypes = {\n finishAuthUrl: PropTypes.string,\n success: PropTypes.bool,\n redirectUrl: PropTypes.string,\n redirectToProgressiveProfilingForm: PropTypes.bool,\n isLinkTracked: PropTypes.bool,\n};\n\nexport default AuthenticatedRedirection;\n"],"mappings":"AAAA,SAASA,SAAS,QAAQ,wBAAwB;AAClD,OAAOC,SAAS,MAAM,YAAY;AAElC,SAASC,oBAAoB,QAAQ,qCAAqC;AAC1E,SAASC,0BAA0B,QAAQ,sBAAsB;AACjE,SAASC,YAAY,QAAQ,0BAA0B;AACvD,SAASC,WAAW,QAAQ,uBAAuB;AACnD,SAASC,SAAS,QAAQ,kBAAkB;AAC5C,SACEC,kCAAkC,QAC7B,8CAA8C;;AAErD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,wBAAwB,GAAGC,IAAA,IAM3B;EAAA,IAN4B;IAChCC,aAAa,GAAG,IAAI;IACpBC,WAAW,GAAG,EAAE;IAChBC,kCAAkC,GAAG,KAAK;IAC1CC,OAAO,GAAG,KAAK;IACfC,aAAa,GAAG;EAClB,CAAC,GAAAL,IAAA;EACC,MAAMM,QAAQ,GAAGV,WAAW,CAAC,CAAC;EAE9B,IAAIQ,OAAO,EAAE;IACX,IAAIG,gBAAgB,GAAG,EAAE;;IAEzB;IACA;IACA;IACA;IACA,IAAIN,aAAa,IAAI,CAACC,WAAW,CAACM,QAAQ,CAACP,aAAa,CAAC,EAAE;MACzDM,gBAAgB,GAAGhB,SAAS,CAAC,CAAC,CAACkB,YAAY,GAAGR,aAAa;IAC7D,CAAC,MAAM;MACLM,gBAAgB,GAAGL,WAAW;IAChC;;IAEA;IACA,IAAIC,kCAAkC,EAAE;MACtC;MACAN,SAAS,CAAC,wBAAwB,EAAE,IAAI,CAAC;MAEzCS,QAAQ,CAACR,kCAAkC,CAACS,gBAAgB,CAAC,CAAC;MAC9DD,QAAQ,CAACb,oBAAoB,CAACC,0BAA0B,CAAC,CAAC;MAC1D,OAAO,IAAI;IACb;IAEA,IAAIW,aAAa,EAAE;MACjBK,UAAU,CAAC,MAAM;QAAEC,MAAM,CAACC,QAAQ,CAACC,IAAI,GAAGN,gBAAgB;MAAE,CAAC,EAAEZ,YAAY,CAAC;IAC9E,CAAC,MAAM;MACLgB,MAAM,CAACC,QAAQ,CAACC,IAAI,GAAGN,gBAAgB;IACzC;EACF;EAEA,OAAO,IAAI;AACb,CAAC;AAEDR,wBAAwB,CAACe,SAAS,GAAG;EACnCb,aAAa,EAAET,SAAS,CAACuB,MAAM;EAC/BX,OAAO,EAAEZ,SAAS,CAACwB,IAAI;EACvBd,WAAW,EAAEV,SAAS,CAACuB,MAAM;EAC7BZ,kCAAkC,EAAEX,SAAS,CAACwB,IAAI;EAClDX,aAAa,EAAEb,SAAS,CAACwB;AAC3B,CAAC;AAED,eAAejB,wBAAwB","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/common-components/SSOFailureAlert.js b/dist/forms/common-components/SSOFailureAlert.js new file mode 100644 index 00000000..0169d1d7 --- /dev/null +++ b/dist/forms/common-components/SSOFailureAlert.js @@ -0,0 +1,45 @@ +import React from 'react'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Alert } from '@openedx/paragon'; +import PropTypes from 'prop-types'; +import messages from './messages'; +import { TPA_AUTHENTICATION_FAILURE } from '../../data/constants'; + +/** + * SSOFailureAlert component displays an error alert based on the provided error code. + * It accepts the following props: + * - errorCode: The error code indicating the type of error. + * - context: Additional context for the error, such as error message. + * - alertTitle: Optional title for the alert. + */ +const SSOFailureAlert = props => { + const { + formatMessage + } = useIntl(); + const { + context = {}, + errorCode, + alertTitle = null + } = props; + if (!errorCode || errorCode !== TPA_AUTHENTICATION_FAILURE) { + return null; + } + const errorMessage = errorCode === TPA_AUTHENTICATION_FAILURE ? /*#__PURE__*/React.createElement("span", null, formatMessage(messages.TPAAuthenticationFailure, { + lineBreak: /*#__PURE__*/React.createElement("br", null), + errorMessage: context.errorMessage + })) : null; + return /*#__PURE__*/React.createElement(Alert, { + id: "SSO-failure-alert", + className: "mb-4", + variant: "danger" + }, alertTitle && /*#__PURE__*/React.createElement("span", null, alertTitle), " ", errorMessage); +}; +SSOFailureAlert.propTypes = { + context: PropTypes.shape({ + errorMessage: PropTypes.string + }), + errorCode: PropTypes.string.isRequired, + alertTitle: PropTypes.node +}; +export default SSOFailureAlert; +//# sourceMappingURL=SSOFailureAlert.js.map \ No newline at end of file diff --git a/dist/forms/common-components/SSOFailureAlert.js.map b/dist/forms/common-components/SSOFailureAlert.js.map new file mode 100644 index 00000000..b96fffeb --- /dev/null +++ b/dist/forms/common-components/SSOFailureAlert.js.map @@ -0,0 +1 @@ +{"version":3,"file":"SSOFailureAlert.js","names":["React","useIntl","Alert","PropTypes","messages","TPA_AUTHENTICATION_FAILURE","SSOFailureAlert","props","formatMessage","context","errorCode","alertTitle","errorMessage","createElement","TPAAuthenticationFailure","lineBreak","id","className","variant","propTypes","shape","string","isRequired","node"],"sources":["../../../src/forms/common-components/SSOFailureAlert.jsx"],"sourcesContent":["import React from 'react';\n\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport { Alert } from '@openedx/paragon';\nimport PropTypes from 'prop-types';\n\nimport messages from './messages';\nimport { TPA_AUTHENTICATION_FAILURE } from '../../data/constants';\n\n/**\n * SSOFailureAlert component displays an error alert based on the provided error code.\n * It accepts the following props:\n * - errorCode: The error code indicating the type of error.\n * - context: Additional context for the error, such as error message.\n * - alertTitle: Optional title for the alert.\n */\nconst SSOFailureAlert = (props) => {\n const { formatMessage } = useIntl();\n const { context = {}, errorCode, alertTitle = null } = props;\n\n if (!errorCode || errorCode !== TPA_AUTHENTICATION_FAILURE) {\n return null;\n }\n const errorMessage = errorCode === TPA_AUTHENTICATION_FAILURE\n ? (\n \n {formatMessage(messages.TPAAuthenticationFailure, {\n lineBreak:
,\n errorMessage: context.errorMessage,\n })}\n
\n )\n : null;\n\n return (\n \n {alertTitle && {alertTitle}} {errorMessage}\n \n );\n};\n\nSSOFailureAlert.propTypes = {\n context: PropTypes.shape({\n errorMessage: PropTypes.string,\n }),\n errorCode: PropTypes.string.isRequired,\n alertTitle: PropTypes.node,\n};\n\nexport default SSOFailureAlert;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AAEzB,SAASC,OAAO,QAAQ,6BAA6B;AACrD,SAASC,KAAK,QAAQ,kBAAkB;AACxC,OAAOC,SAAS,MAAM,YAAY;AAElC,OAAOC,QAAQ,MAAM,YAAY;AACjC,SAASC,0BAA0B,QAAQ,sBAAsB;;AAEjE;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,eAAe,GAAIC,KAAK,IAAK;EACjC,MAAM;IAAEC;EAAc,CAAC,GAAGP,OAAO,CAAC,CAAC;EACnC,MAAM;IAAEQ,OAAO,GAAG,CAAC,CAAC;IAAEC,SAAS;IAAEC,UAAU,GAAG;EAAK,CAAC,GAAGJ,KAAK;EAE5D,IAAI,CAACG,SAAS,IAAIA,SAAS,KAAKL,0BAA0B,EAAE;IAC1D,OAAO,IAAI;EACb;EACA,MAAMO,YAAY,GAAGF,SAAS,KAAKL,0BAA0B,gBAEzDL,KAAA,CAAAa,aAAA,eACGL,aAAa,CAACJ,QAAQ,CAACU,wBAAwB,EAAE;IAChDC,SAAS,eAAEf,KAAA,CAAAa,aAAA,WAAK,CAAC;IACjBD,YAAY,EAAEH,OAAO,CAACG;EACxB,CAAC,CACG,CAAC,GAEP,IAAI;EAER,oBACEZ,KAAA,CAAAa,aAAA,CAACX,KAAK;IAACc,EAAE,EAAC,mBAAmB;IAACC,SAAS,EAAC,MAAM;IAACC,OAAO,EAAC;EAAQ,GAC5DP,UAAU,iBAAIX,KAAA,CAAAa,aAAA,eAAOF,UAAiB,CAAC,EAAC,GAAC,EAACC,YACtC,CAAC;AAEZ,CAAC;AAEDN,eAAe,CAACa,SAAS,GAAG;EAC1BV,OAAO,EAAEN,SAAS,CAACiB,KAAK,CAAC;IACvBR,YAAY,EAAET,SAAS,CAACkB;EAC1B,CAAC,CAAC;EACFX,SAAS,EAAEP,SAAS,CAACkB,MAAM,CAACC,UAAU;EACtCX,UAAU,EAAER,SAAS,CAACoB;AACxB,CAAC;AAED,eAAejB,eAAe","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/common-components/ThirdPartyAuthAlert.js b/dist/forms/common-components/ThirdPartyAuthAlert.js new file mode 100644 index 00000000..c2ed6c50 --- /dev/null +++ b/dist/forms/common-components/ThirdPartyAuthAlert.js @@ -0,0 +1,46 @@ +import React from 'react'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Alert } from '@openedx/paragon'; +import PropTypes from 'prop-types'; +import messages from './messages'; +import { LOGIN_FORM } from '../../data/constants'; + +/** + * Component for displaying an alert related to third-party authentication. + * + * @param {string} currentProvider - The name of the current authentication provider. + * @param {string} referrer - The referrer (either 'login' or 'register') to determine the message and styling. + * + * @returns {JSX.Element} The rendered alert component. + */ +const ThirdPartyAuthAlert = _ref => { + let { + currentProvider = '', + referrer = LOGIN_FORM + } = _ref; + const { + formatMessage + } = useIntl(); + const platformName = 'edX'; + if (!currentProvider) { + return null; + } + const message = referrer === LOGIN_FORM ? formatMessage(messages.loginTpaAccountNotLinked, { + currentProvider, + platformName + }) : formatMessage(messages.registerTpaAccountNotLinked, { + currentProvider, + platformName + }); + const alertClassName = referrer === LOGIN_FORM ? 'alert-warning mt-n2 mb-5' : 'alert-success mt-n2 mb-5'; + return /*#__PURE__*/React.createElement(Alert, { + id: "tpa-alert", + className: alertClassName + }, /*#__PURE__*/React.createElement("p", null, message)); +}; +ThirdPartyAuthAlert.propTypes = { + currentProvider: PropTypes.string, + referrer: PropTypes.string +}; +export default ThirdPartyAuthAlert; +//# sourceMappingURL=ThirdPartyAuthAlert.js.map \ No newline at end of file diff --git a/dist/forms/common-components/ThirdPartyAuthAlert.js.map b/dist/forms/common-components/ThirdPartyAuthAlert.js.map new file mode 100644 index 00000000..3345ed78 --- /dev/null +++ b/dist/forms/common-components/ThirdPartyAuthAlert.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ThirdPartyAuthAlert.js","names":["React","useIntl","Alert","PropTypes","messages","LOGIN_FORM","ThirdPartyAuthAlert","_ref","currentProvider","referrer","formatMessage","platformName","message","loginTpaAccountNotLinked","registerTpaAccountNotLinked","alertClassName","createElement","id","className","propTypes","string"],"sources":["../../../src/forms/common-components/ThirdPartyAuthAlert.jsx"],"sourcesContent":["import React from 'react';\n\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport { Alert } from '@openedx/paragon';\nimport PropTypes from 'prop-types';\n\nimport messages from './messages';\nimport { LOGIN_FORM } from '../../data/constants';\n\n/**\n * Component for displaying an alert related to third-party authentication.\n *\n * @param {string} currentProvider - The name of the current authentication provider.\n * @param {string} referrer - The referrer (either 'login' or 'register') to determine the message and styling.\n *\n * @returns {JSX.Element} The rendered alert component.\n */\nconst ThirdPartyAuthAlert = ({\n currentProvider = '',\n referrer = LOGIN_FORM,\n}) => {\n const { formatMessage } = useIntl();\n const platformName = 'edX';\n\n if (!currentProvider) {\n return null;\n }\n\n const message = referrer === LOGIN_FORM\n ? formatMessage(messages.loginTpaAccountNotLinked, { currentProvider, platformName })\n : formatMessage(messages.registerTpaAccountNotLinked, { currentProvider, platformName });\n const alertClassName = referrer === LOGIN_FORM ? 'alert-warning mt-n2 mb-5' : 'alert-success mt-n2 mb-5';\n\n return (\n \n

{ message }

\n
\n );\n};\n\nThirdPartyAuthAlert.propTypes = {\n currentProvider: PropTypes.string,\n referrer: PropTypes.string,\n};\n\nexport default ThirdPartyAuthAlert;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AAEzB,SAASC,OAAO,QAAQ,6BAA6B;AACrD,SAASC,KAAK,QAAQ,kBAAkB;AACxC,OAAOC,SAAS,MAAM,YAAY;AAElC,OAAOC,QAAQ,MAAM,YAAY;AACjC,SAASC,UAAU,QAAQ,sBAAsB;;AAEjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,mBAAmB,GAAGC,IAAA,IAGtB;EAAA,IAHuB;IAC3BC,eAAe,GAAG,EAAE;IACpBC,QAAQ,GAAGJ;EACb,CAAC,GAAAE,IAAA;EACC,MAAM;IAAEG;EAAc,CAAC,GAAGT,OAAO,CAAC,CAAC;EACnC,MAAMU,YAAY,GAAG,KAAK;EAE1B,IAAI,CAACH,eAAe,EAAE;IACpB,OAAO,IAAI;EACb;EAEA,MAAMI,OAAO,GAAGH,QAAQ,KAAKJ,UAAU,GACnCK,aAAa,CAACN,QAAQ,CAACS,wBAAwB,EAAE;IAAEL,eAAe;IAAEG;EAAa,CAAC,CAAC,GACnFD,aAAa,CAACN,QAAQ,CAACU,2BAA2B,EAAE;IAAEN,eAAe;IAAEG;EAAa,CAAC,CAAC;EAC1F,MAAMI,cAAc,GAAGN,QAAQ,KAAKJ,UAAU,GAAG,0BAA0B,GAAG,0BAA0B;EAExG,oBACEL,KAAA,CAAAgB,aAAA,CAACd,KAAK;IAACe,EAAE,EAAC,WAAW;IAACC,SAAS,EAAEH;EAAe,gBAC9Cf,KAAA,CAAAgB,aAAA,YAAKJ,OAAY,CACZ,CAAC;AAEZ,CAAC;AAEDN,mBAAmB,CAACa,SAAS,GAAG;EAC9BX,eAAe,EAAEL,SAAS,CAACiB,MAAM;EACjCX,QAAQ,EAAEN,SAAS,CAACiB;AACtB,CAAC;AAED,eAAed,mBAAmB","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/common-components/messages.js b/dist/forms/common-components/messages.js new file mode 100644 index 00000000..7838d51b --- /dev/null +++ b/dist/forms/common-components/messages.js @@ -0,0 +1,20 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; +const messages = defineMessages({ + loginTpaAccountNotLinked: { + id: 'login.third.party.auth.account.not.linked', + defaultMessage: 'You have successfully signed into {currentProvider}, but your {currentProvider} ' + 'account does not have a linked {platformName} account. To link your accounts, ' + 'sign in now using your {platformName} password.', + description: 'Message that appears on login page if user has successfully authenticated with social ' + 'auth but no associated platform account exists' + }, + registerTpaAccountNotLinked: { + id: 'register.third.party.auth.account.not.linked', + defaultMessage: 'You\'ve successfully signed into {currentProvider}! We just need a little more information ' + 'before you start learning with {platformName}.', + description: 'Message that appears on register page if user has successfully authenticated with TPA ' + 'but no associated platform account exists' + }, + TPAAuthenticationFailure: { + id: 'tpa.authentication.failure', + defaultMessage: 'We are sorry, you are not authorized to access edX via this channel. ' + 'Please contact your learning administrator or manager in order to access edX.' + '{lineBreak}{lineBreak}Error Details:{lineBreak}{errorMessage}', + description: 'Error message third party authentication pipeline fails' + } +}); +export default messages; +//# sourceMappingURL=messages.js.map \ No newline at end of file diff --git a/dist/forms/common-components/messages.js.map b/dist/forms/common-components/messages.js.map new file mode 100644 index 00000000..2d0bd6ea --- /dev/null +++ b/dist/forms/common-components/messages.js.map @@ -0,0 +1 @@ +{"version":3,"file":"messages.js","names":["defineMessages","messages","loginTpaAccountNotLinked","id","defaultMessage","description","registerTpaAccountNotLinked","TPAAuthenticationFailure"],"sources":["../../../src/forms/common-components/messages.jsx"],"sourcesContent":["import { defineMessages } from '@edx/frontend-platform/i18n';\n\nconst messages = defineMessages({\n loginTpaAccountNotLinked: {\n id: 'login.third.party.auth.account.not.linked',\n defaultMessage: 'You have successfully signed into {currentProvider}, but your {currentProvider} '\n + 'account does not have a linked {platformName} account. To link your accounts, '\n + 'sign in now using your {platformName} password.',\n description: 'Message that appears on login page if user has successfully authenticated with social '\n + 'auth but no associated platform account exists',\n },\n registerTpaAccountNotLinked: {\n id: 'register.third.party.auth.account.not.linked',\n defaultMessage: 'You\\'ve successfully signed into {currentProvider}! We just need a little more information '\n + 'before you start learning with {platformName}.',\n description: 'Message that appears on register page if user has successfully authenticated with TPA '\n + 'but no associated platform account exists',\n },\n TPAAuthenticationFailure: {\n id: 'tpa.authentication.failure',\n defaultMessage: 'We are sorry, you are not authorized to access edX via this channel. '\n + 'Please contact your learning administrator or manager in order to access edX.'\n + '{lineBreak}{lineBreak}Error Details:{lineBreak}{errorMessage}',\n description: 'Error message third party authentication pipeline fails',\n },\n});\n\nexport default messages;\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,6BAA6B;AAE5D,MAAMC,QAAQ,GAAGD,cAAc,CAAC;EAC9BE,wBAAwB,EAAE;IACxBC,EAAE,EAAE,2CAA2C;IAC/CC,cAAc,EAAE,kFAAkF,GAChF,gFAAgF,GAChF,iDAAiD;IACnEC,WAAW,EAAE,wFAAwF,GACrF;EAClB,CAAC;EACDC,2BAA2B,EAAE;IAC3BH,EAAE,EAAE,8CAA8C;IAClDC,cAAc,EAAE,6FAA6F,GAC3F,gDAAgD;IAClEC,WAAW,EAAE,wFAAwF,GACrF;EAClB,CAAC;EACDE,wBAAwB,EAAE;IACxBJ,EAAE,EAAE,4BAA4B;IAChCC,cAAc,EAAE,uEAAuE,GACjF,+EAA+E,GAC/E,+DAA+D;IACrEC,WAAW,EAAE;EACf;AACF,CAAC,CAAC;AAEF,eAAeJ,QAAQ","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/enterprise-sso-popup/data/constants.js b/dist/forms/enterprise-sso-popup/data/constants.js new file mode 100644 index 00000000..73665f43 --- /dev/null +++ b/dist/forms/enterprise-sso-popup/data/constants.js @@ -0,0 +1,4 @@ +// SSO providers +export const SOCIAL_AUTH_PROVIDERS = ['Apple', 'Facebook', 'Google', 'Microsoft']; +export const WHITE_TEXT_COLOR_PROVIDERS = ['Apple', 'Facebook']; +//# sourceMappingURL=constants.js.map \ No newline at end of file diff --git a/dist/forms/enterprise-sso-popup/data/constants.js.map b/dist/forms/enterprise-sso-popup/data/constants.js.map new file mode 100644 index 00000000..341788ae --- /dev/null +++ b/dist/forms/enterprise-sso-popup/data/constants.js.map @@ -0,0 +1 @@ +{"version":3,"file":"constants.js","names":["SOCIAL_AUTH_PROVIDERS","WHITE_TEXT_COLOR_PROVIDERS"],"sources":["../../../../src/forms/enterprise-sso-popup/data/constants.js"],"sourcesContent":["// SSO providers\nexport const SOCIAL_AUTH_PROVIDERS = ['Apple', 'Facebook', 'Google', 'Microsoft'];\nexport const WHITE_TEXT_COLOR_PROVIDERS = ['Apple', 'Facebook'];\n"],"mappings":"AAAA;AACA,OAAO,MAAMA,qBAAqB,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,CAAC;AACjF,OAAO,MAAMC,0BAA0B,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/enterprise-sso-popup/data/utils.js b/dist/forms/enterprise-sso-popup/data/utils.js new file mode 100644 index 00000000..ea6fbdad --- /dev/null +++ b/dist/forms/enterprise-sso-popup/data/utils.js @@ -0,0 +1,35 @@ +// Utility functions +import QueryString from 'query-string'; +export const getTpaProvider = (tpaHintProvider, primaryProviders, secondaryProviders) => { + let tpaProvider = null; + if (!tpaHintProvider) { + return { + provider: tpaProvider + }; + } + [...primaryProviders, ...secondaryProviders].forEach(provider => { + if (provider.id === tpaHintProvider) { + tpaProvider = provider; + } + }); + return { + provider: tpaProvider + }; +}; +export const getTpaHint = () => { + const params = QueryString.parse(window.location.search); + let tpaHint = params.tpa_hint; + if (!tpaHint) { + const { + next + } = params; + if (next) { + const index = next.indexOf('tpa_hint='); + if (index !== -1) { + tpaHint = next.substring(index + 'tpa_hint='.length, next.length); + } + } + } + return tpaHint; +}; +//# sourceMappingURL=utils.js.map \ No newline at end of file diff --git a/dist/forms/enterprise-sso-popup/data/utils.js.map b/dist/forms/enterprise-sso-popup/data/utils.js.map new file mode 100644 index 00000000..d27b2a6e --- /dev/null +++ b/dist/forms/enterprise-sso-popup/data/utils.js.map @@ -0,0 +1 @@ +{"version":3,"file":"utils.js","names":["QueryString","getTpaProvider","tpaHintProvider","primaryProviders","secondaryProviders","tpaProvider","provider","forEach","id","getTpaHint","params","parse","window","location","search","tpaHint","tpa_hint","next","index","indexOf","substring","length"],"sources":["../../../../src/forms/enterprise-sso-popup/data/utils.js"],"sourcesContent":["// Utility functions\nimport QueryString from 'query-string';\n\nexport const getTpaProvider = (tpaHintProvider, primaryProviders, secondaryProviders) => {\n let tpaProvider = null;\n if (!tpaHintProvider) {\n return { provider: tpaProvider };\n }\n [...primaryProviders, ...secondaryProviders].forEach((provider) => {\n if (provider.id === tpaHintProvider) {\n tpaProvider = provider;\n }\n });\n return { provider: tpaProvider };\n};\n\nexport const getTpaHint = () => {\n const params = QueryString.parse(window.location.search);\n let tpaHint = params.tpa_hint;\n if (!tpaHint) {\n const { next } = params;\n if (next) {\n const index = next.indexOf('tpa_hint=');\n if (index !== -1) {\n tpaHint = next.substring(index + 'tpa_hint='.length, next.length);\n }\n }\n }\n return tpaHint;\n};\n"],"mappings":"AAAA;AACA,OAAOA,WAAW,MAAM,cAAc;AAEtC,OAAO,MAAMC,cAAc,GAAGA,CAACC,eAAe,EAAEC,gBAAgB,EAAEC,kBAAkB,KAAK;EACvF,IAAIC,WAAW,GAAG,IAAI;EACtB,IAAI,CAACH,eAAe,EAAE;IACpB,OAAO;MAAEI,QAAQ,EAAED;IAAY,CAAC;EAClC;EACA,CAAC,GAAGF,gBAAgB,EAAE,GAAGC,kBAAkB,CAAC,CAACG,OAAO,CAAED,QAAQ,IAAK;IACjE,IAAIA,QAAQ,CAACE,EAAE,KAAKN,eAAe,EAAE;MACnCG,WAAW,GAAGC,QAAQ;IACxB;EACF,CAAC,CAAC;EACF,OAAO;IAAEA,QAAQ,EAAED;EAAY,CAAC;AAClC,CAAC;AAED,OAAO,MAAMI,UAAU,GAAGA,CAAA,KAAM;EAC9B,MAAMC,MAAM,GAAGV,WAAW,CAACW,KAAK,CAACC,MAAM,CAACC,QAAQ,CAACC,MAAM,CAAC;EACxD,IAAIC,OAAO,GAAGL,MAAM,CAACM,QAAQ;EAC7B,IAAI,CAACD,OAAO,EAAE;IACZ,MAAM;MAAEE;IAAK,CAAC,GAAGP,MAAM;IACvB,IAAIO,IAAI,EAAE;MACR,MAAMC,KAAK,GAAGD,IAAI,CAACE,OAAO,CAAC,WAAW,CAAC;MACvC,IAAID,KAAK,KAAK,CAAC,CAAC,EAAE;QAChBH,OAAO,GAAGE,IAAI,CAACG,SAAS,CAACF,KAAK,GAAG,WAAW,CAACG,MAAM,EAAEJ,IAAI,CAACI,MAAM,CAAC;MACnE;IACF;EACF;EACA,OAAON,OAAO;AAChB,CAAC","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/enterprise-sso-popup/index.js b/dist/forms/enterprise-sso-popup/index.js new file mode 100644 index 00000000..345fa1a5 --- /dev/null +++ b/dist/forms/enterprise-sso-popup/index.js @@ -0,0 +1,98 @@ +import React, { useEffect, useRef } from 'react'; +import { getConfig } from '@edx/frontend-platform'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Button, Icon } from '@openedx/paragon'; +import { Login } from '@openedx/paragon/icons'; +import PropTypes from 'prop-types'; +import './index.scss'; +import { SOCIAL_AUTH_PROVIDERS, WHITE_TEXT_COLOR_PROVIDERS } from './data/constants'; +import messages from './messages'; +import { setCurrentOpenedForm } from '../../authn-component/data/reducers'; +import { SocialAuthButton as EnterpriseSSOButton } from '../../common-ui/SocialAuthButtons'; +import { LOGIN_FORM } from '../../data/constants'; +import { useDispatch } from '../../data/storeHooks'; +/** + * This component renders the Single sign-on (SSO) button only for the tpa provider passed + * + * @returns {JSX.Element} rendered EnterpriseSSO component. + */ +const EnterpriseSSO = props => { + const { + formatMessage + } = useIntl(); + const dispatch = useDispatch(); + const { + provider = { + id: '', + name: '', + loginUrl: '', + registerUrl: '' + } + } = props; + const inverseTextColor = WHITE_TEXT_COLOR_PROVIDERS.includes(provider.name); + const buttonRef = useRef(null); + useEffect(() => { + if (buttonRef.current) { + buttonRef.current.focus(); + } + }, []); + const handleClick = (e, url) => { + e.preventDefault(); + window.location.href = getConfig().LMS_BASE_URL + url; + }; + const redirectToLogin = e => { + e.preventDefault(); + dispatch(setCurrentOpenedForm(LOGIN_FORM)); + }; + if (provider) { + return /*#__PURE__*/React.createElement("div", { + className: "authn__popup-container d-flex flex-column w-100" + }, /*#__PURE__*/React.createElement("p", null, formatMessage(messages.enterprisetpaTitleHeading, { + providerName: provider.name + })), SOCIAL_AUTH_PROVIDERS.includes(provider.name) ? /*#__PURE__*/React.createElement(EnterpriseSSOButton, { + provider: provider, + isLoginForm: true, + inverseTextColor: inverseTextColor, + ref: buttonRef + }) : /*#__PURE__*/React.createElement(Button, { + id: provider.id, + name: provider.id, + variant: "inverse-primary", + className: "w-100 text-black-50 d-flex flex-row justify-content-start align-items-center pl-3 authn-sso-btn__pill-shaped", + onClick: e => handleClick(e, provider.loginUrl), + ref: buttonRef + }, /*#__PURE__*/React.createElement("div", { + className: "btn-tpa__font-container", + "aria-hidden": "true" + }, /*#__PURE__*/React.createElement(Icon, { + className: "h-75", + src: Login + })), /*#__PURE__*/React.createElement("span", { + className: "pl-2", + "aria-hidden": "true" + }, formatMessage(messages.enterpriseTpaProviderSigninTitle, { + providerName: provider.name + }))), /*#__PURE__*/React.createElement("div", { + className: "mb-4" + }), /*#__PURE__*/React.createElement(Button, { + id: "other-ways-to-sign-in", + name: "other-ways-to-sign-in", + variant: "primary", + state: "Complete", + className: "w-100 authn-btn__pill-shaped", + onClick: redirectToLogin, + onMouseDown: e => e.preventDefault() + }, formatMessage(messages.enterprisetpaLoginButtonText))); + } + return null; +}; +EnterpriseSSO.propTypes = { + provider: PropTypes.shape({ + id: PropTypes.string, + name: PropTypes.string, + loginUrl: PropTypes.string, + registerUrl: PropTypes.string + }) +}; +export default EnterpriseSSO; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/forms/enterprise-sso-popup/index.js.map b/dist/forms/enterprise-sso-popup/index.js.map new file mode 100644 index 00000000..57daf41a --- /dev/null +++ b/dist/forms/enterprise-sso-popup/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["React","useEffect","useRef","getConfig","useIntl","Button","Icon","Login","PropTypes","SOCIAL_AUTH_PROVIDERS","WHITE_TEXT_COLOR_PROVIDERS","messages","setCurrentOpenedForm","SocialAuthButton","EnterpriseSSOButton","LOGIN_FORM","useDispatch","EnterpriseSSO","props","formatMessage","dispatch","provider","id","name","loginUrl","registerUrl","inverseTextColor","includes","buttonRef","current","focus","handleClick","e","url","preventDefault","window","location","href","LMS_BASE_URL","redirectToLogin","createElement","className","enterprisetpaTitleHeading","providerName","isLoginForm","ref","variant","onClick","src","enterpriseTpaProviderSigninTitle","state","onMouseDown","enterprisetpaLoginButtonText","propTypes","shape","string"],"sources":["../../../src/forms/enterprise-sso-popup/index.jsx"],"sourcesContent":["import React, { useEffect, useRef } from 'react';\n\nimport { getConfig } from '@edx/frontend-platform';\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport { Button, Icon } from '@openedx/paragon';\nimport { Login } from '@openedx/paragon/icons';\nimport PropTypes from 'prop-types';\n\nimport './index.scss';\nimport { SOCIAL_AUTH_PROVIDERS, WHITE_TEXT_COLOR_PROVIDERS } from './data/constants';\nimport messages from './messages';\nimport { setCurrentOpenedForm } from '../../authn-component/data/reducers';\nimport { SocialAuthButton as EnterpriseSSOButton } from '../../common-ui/SocialAuthButtons';\nimport { LOGIN_FORM } from '../../data/constants';\nimport { useDispatch } from '../../data/storeHooks';\n/**\n * This component renders the Single sign-on (SSO) button only for the tpa provider passed\n *\n * @returns {JSX.Element} rendered EnterpriseSSO component.\n */\nconst EnterpriseSSO = (props) => {\n const { formatMessage } = useIntl();\n const dispatch = useDispatch();\n const {\n provider = {\n id: '',\n name: '',\n loginUrl: '',\n registerUrl: '',\n },\n } = props;\n const inverseTextColor = WHITE_TEXT_COLOR_PROVIDERS.includes(provider.name);\n const buttonRef = useRef(null);\n useEffect(() => {\n if (buttonRef.current) {\n buttonRef.current.focus();\n }\n }, []);\n\n const handleClick = (e, url) => {\n e.preventDefault();\n window.location.href = getConfig().LMS_BASE_URL + url;\n };\n\n const redirectToLogin = (e) => {\n e.preventDefault();\n dispatch(setCurrentOpenedForm(LOGIN_FORM));\n };\n\n if (provider) {\n return (\n
\n

{formatMessage(messages.enterprisetpaTitleHeading, { providerName: provider.name })}

\n {SOCIAL_AUTH_PROVIDERS.includes(provider.name) ? (\n \n ) : (\n handleClick(e, provider.loginUrl)}\n ref={buttonRef}\n >\n
\n \n
\n \n {formatMessage(messages.enterpriseTpaProviderSigninTitle, { providerName: provider.name })}\n \n \n )}\n
\n e.preventDefault()}\n >\n {formatMessage(messages.enterprisetpaLoginButtonText)}\n \n
\n );\n }\n return null;\n};\n\nEnterpriseSSO.propTypes = {\n provider: PropTypes.shape({\n id: PropTypes.string,\n name: PropTypes.string,\n loginUrl: PropTypes.string,\n registerUrl: PropTypes.string,\n }),\n};\n\nexport default EnterpriseSSO;\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/enterprise-sso-popup/index.scss b/dist/forms/enterprise-sso-popup/index.scss new file mode 100644 index 00000000..a6d03153 --- /dev/null +++ b/dist/forms/enterprise-sso-popup/index.scss @@ -0,0 +1,11 @@ +@import "~@edx/brand-edx.org/paragon/variables"; + +.btn-tpa__font-container { + background-color: $primary !important; + color: $white !important; + font-size: 11px !important; + margin-left: -6px !important; + padding-top: 5px !important; + min-width: 24px !important; + height: 24px !important; +} diff --git a/dist/forms/enterprise-sso-popup/messages.js b/dist/forms/enterprise-sso-popup/messages.js new file mode 100644 index 00000000..ca8c32b7 --- /dev/null +++ b/dist/forms/enterprise-sso-popup/messages.js @@ -0,0 +1,20 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; +const messages = defineMessages({ + enterprisetpaTitleHeading: { + id: 'enterprisetpa.title.heading', + defaultMessage: 'Would you like to sign in using your {providerName} credentials?', + description: 'Header text used in enterprise third party authentication' + }, + enterprisetpaLoginButtonText: { + id: 'enterprisetpa.login.button.text', + defaultMessage: 'Show me other ways to sign in or register', + description: 'Button text for login' + }, + enterpriseTpaProviderSigninTitle: { + id: 'social.auth.provide.signin.title', + defaultMessage: 'Sign in with {providerName}', + description: 'Title that appears on the TPA provider buttons i.e Sign in with Google' + } +}); +export default messages; +//# sourceMappingURL=messages.js.map \ No newline at end of file diff --git a/dist/forms/enterprise-sso-popup/messages.js.map b/dist/forms/enterprise-sso-popup/messages.js.map new file mode 100644 index 00000000..6ff2cc19 --- /dev/null +++ b/dist/forms/enterprise-sso-popup/messages.js.map @@ -0,0 +1 @@ +{"version":3,"file":"messages.js","names":["defineMessages","messages","enterprisetpaTitleHeading","id","defaultMessage","description","enterprisetpaLoginButtonText","enterpriseTpaProviderSigninTitle"],"sources":["../../../src/forms/enterprise-sso-popup/messages.js"],"sourcesContent":["import { defineMessages } from '@edx/frontend-platform/i18n';\n\nconst messages = defineMessages({\n enterprisetpaTitleHeading: {\n id: 'enterprisetpa.title.heading',\n defaultMessage: 'Would you like to sign in using your {providerName} credentials?',\n description: 'Header text used in enterprise third party authentication',\n },\n enterprisetpaLoginButtonText: {\n id: 'enterprisetpa.login.button.text',\n defaultMessage: 'Show me other ways to sign in or register',\n description: 'Button text for login',\n },\n enterpriseTpaProviderSigninTitle: {\n id: 'social.auth.provide.signin.title',\n defaultMessage: 'Sign in with {providerName}',\n description: 'Title that appears on the TPA provider buttons i.e Sign in with Google',\n },\n});\n\nexport default messages;\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,6BAA6B;AAE5D,MAAMC,QAAQ,GAAGD,cAAc,CAAC;EAC9BE,yBAAyB,EAAE;IACzBC,EAAE,EAAE,6BAA6B;IACjCC,cAAc,EAAE,kEAAkE;IAClFC,WAAW,EAAE;EACf,CAAC;EACDC,4BAA4B,EAAE;IAC5BH,EAAE,EAAE,iCAAiC;IACrCC,cAAc,EAAE,2CAA2C;IAC3DC,WAAW,EAAE;EACf,CAAC;EACDE,gCAAgC,EAAE;IAChCJ,EAAE,EAAE,kCAAkC;IACtCC,cAAc,EAAE,6BAA6B;IAC7CC,WAAW,EAAE;EACf;AACF,CAAC,CAAC;AAEF,eAAeJ,QAAQ","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/fields/auto-suggested-field/index.js b/dist/forms/fields/auto-suggested-field/index.js new file mode 100644 index 00000000..a4050657 --- /dev/null +++ b/dist/forms/fields/auto-suggested-field/index.js @@ -0,0 +1,137 @@ +function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } +function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } +function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); } +function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } +import React, { useEffect, useState } from 'react'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { FormAutosuggest, FormAutosuggestOption, FormControlFeedback, FormLabel } from '@openedx/paragon'; +import classNames from 'classnames'; +import PropTypes from 'prop-types'; +import messages from '../../progressive-profiling-popup/messages'; +import './index.scss'; + +/** + * Auto Suggest field wrapper. It accepts following handlers + * - handleChange for setting value on change + * - onFocusHandler for clearing error state + * - onBlurHandler for setting error on null value + * + * It is responsible for + * - Auto populating progressive profiling fields + * - setting value on change and selection + */ +const AutoSuggestField = props => { + const { + name, + label = '', + placeholder, + feedBack = '', + errorMessage = '', + options, + selectedOption = { + value: '', + displayText: '' + }, + leadingElement = '', + onChangeHandler, + onFocusHandler = () => {}, + onBlurHandler = () => {} + } = props; + const { + formatMessage + } = useIntl(); + const [value, setValue] = useState({}); + useEffect(() => { + if (name === 'country' && selectedOption.value !== '' && !value.country) { + setValue(_objectSpread(_objectSpread({}, value), {}, { + [name]: { + userProvidedText: selectedOption?.displayText, + selectionValue: selectedOption?.value, + selectionId: selectedOption?.value + } + })); + } + }, [name, selectedOption, value]); + const handleOnChange = (e, fieldName) => { + setValue(_objectSpread(_objectSpread({}, value), {}, { + [fieldName]: e + })); + onChangeHandler({ + target: { + name, + value: e.selectionId, + text: e.userProvidedText + } + }); + }; + const getFieldOptions = (fieldName, fieldOptions) => fieldOptions.map(option => { + if (fieldName === 'country') { + return /*#__PURE__*/React.createElement(FormAutosuggestOption, { + id: option.code, + key: option.code + }, option.name); + } + return /*#__PURE__*/React.createElement(FormAutosuggestOption, { + id: option.label, + key: option.label + }, messages[`${fieldName}.option.${option.label}`] ? formatMessage(messages[`${fieldName}.option.${option.label}`]) : option.label); + }); + return /*#__PURE__*/React.createElement("div", { + className: "mb-4" + }, name !== 'country' && /*#__PURE__*/React.createElement(FormLabel, null, label), /*#__PURE__*/React.createElement(FormAutosuggest, { + placeholder: placeholder, + "aria-label": "form autosuggest", + name: name, + value: value[name] || {}, + leadingElement: leadingElement, + className: classNames({ + 'form-field-error': errorMessage + }), + onChange: e => { + handleOnChange(e, name); + }, + onFocus: () => { + onFocusHandler({ + target: { + name, + value: '' + } + }); + }, + onBlur: () => { + onBlurHandler({ + target: { + name, + value: value[name] ? value[name].selectionId : '' + } + }); + } + }, getFieldOptions(name, options)), (errorMessage !== '' || feedBack !== '') && /*#__PURE__*/React.createElement(FormControlFeedback, { + key: errorMessage ? 'error' : 'feedback', + hasIcon: false, + "feedback-for": name, + type: errorMessage ? 'invalid' : 'valid' + }, errorMessage || feedBack)); +}; +AutoSuggestField.propTypes = { + name: PropTypes.string.isRequired, + label: PropTypes.string, + placeholder: PropTypes.string.isRequired, + options: PropTypes.arrayOf(PropTypes.shape({ + code: PropTypes.string, + displayText: PropTypes.string + })).isRequired, + errorMessage: PropTypes.string, + feedBack: PropTypes.string, + leadingElement: PropTypes.node, + onChangeHandler: PropTypes.func.isRequired, + onFocusHandler: PropTypes.func, + onBlurHandler: PropTypes.func, + selectedOption: PropTypes.shape({ + displayText: PropTypes.string, + value: PropTypes.string + }) +}; +export default AutoSuggestField; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/forms/fields/auto-suggested-field/index.js.map b/dist/forms/fields/auto-suggested-field/index.js.map new file mode 100644 index 00000000..d8cb678e --- /dev/null +++ b/dist/forms/fields/auto-suggested-field/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["React","useEffect","useState","useIntl","FormAutosuggest","FormAutosuggestOption","FormControlFeedback","FormLabel","classNames","PropTypes","messages","AutoSuggestField","props","name","label","placeholder","feedBack","errorMessage","options","selectedOption","value","displayText","leadingElement","onChangeHandler","onFocusHandler","onBlurHandler","formatMessage","setValue","country","_objectSpread","userProvidedText","selectionValue","selectionId","handleOnChange","e","fieldName","target","text","getFieldOptions","fieldOptions","map","option","createElement","id","code","key","className","onChange","onFocus","onBlur","hasIcon","type","propTypes","string","isRequired","arrayOf","shape","node","func"],"sources":["../../../../src/forms/fields/auto-suggested-field/index.jsx"],"sourcesContent":["import React, { useEffect, useState } from 'react';\n\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport {\n FormAutosuggest,\n FormAutosuggestOption,\n FormControlFeedback,\n FormLabel,\n} from '@openedx/paragon';\nimport classNames from 'classnames';\nimport PropTypes from 'prop-types';\n\nimport messages from '../../progressive-profiling-popup/messages';\nimport './index.scss';\n\n/**\n * Auto Suggest field wrapper. It accepts following handlers\n * - handleChange for setting value on change\n * - onFocusHandler for clearing error state\n * - onBlurHandler for setting error on null value\n *\n * It is responsible for\n * - Auto populating progressive profiling fields\n * - setting value on change and selection\n */\nconst AutoSuggestField = (props) => {\n const {\n name,\n label = '',\n placeholder,\n feedBack = '',\n errorMessage = '',\n options,\n selectedOption = {\n value: '',\n displayText: '',\n },\n leadingElement = '',\n onChangeHandler,\n onFocusHandler = () => {},\n onBlurHandler = () => {},\n } = props;\n const { formatMessage } = useIntl();\n const [value, setValue] = useState({});\n\n useEffect(() => {\n if (name === 'country'\n && selectedOption.value !== ''\n && !value.country\n ) {\n setValue({\n ...value,\n [name]: {\n userProvidedText: selectedOption?.displayText,\n selectionValue: selectedOption?.value,\n selectionId: selectedOption?.value,\n },\n });\n }\n }, [name, selectedOption, value]);\n\n const handleOnChange = (e, fieldName) => {\n setValue({\n ...value,\n [fieldName]: e,\n });\n onChangeHandler({ target: { name, value: e.selectionId, text: e.userProvidedText } });\n };\n\n const getFieldOptions = (fieldName, fieldOptions) => fieldOptions.map(option => {\n if (fieldName === 'country') {\n return (\n {option.name}\n );\n }\n return (\n \n {\n messages[`${fieldName}.option.${option.label}`]\n ? formatMessage(messages[`${fieldName}.option.${option.label}`])\n : option.label\n }\n \n );\n });\n\n return (\n
\n {name !== 'country' && {label}}\n { handleOnChange(e, name); }}\n onFocus={() => { onFocusHandler({ target: { name, value: '' } }); }}\n onBlur={() => { onBlurHandler({ target: { name, value: value[name] ? value[name].selectionId : '' } }); }}\n >\n {getFieldOptions(name, options)}\n \n {(errorMessage !== '' || feedBack !== '') && (\n \n {errorMessage || feedBack}\n \n )}\n
\n );\n};\n\nAutoSuggestField.propTypes = {\n name: PropTypes.string.isRequired,\n label: PropTypes.string,\n placeholder: PropTypes.string.isRequired,\n options: PropTypes.arrayOf(\n PropTypes.shape({\n code: PropTypes.string,\n displayText: PropTypes.string,\n }),\n ).isRequired,\n errorMessage: PropTypes.string,\n feedBack: PropTypes.string,\n leadingElement: PropTypes.node,\n onChangeHandler: PropTypes.func.isRequired,\n onFocusHandler: PropTypes.func,\n onBlurHandler: PropTypes.func,\n selectedOption: PropTypes.shape({\n displayText: PropTypes.string,\n value: PropTypes.string,\n }),\n};\n\nexport default AutoSuggestField;\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/fields/auto-suggested-field/index.scss b/dist/forms/fields/auto-suggested-field/index.scss new file mode 100644 index 00000000..490231ba --- /dev/null +++ b/dist/forms/fields/auto-suggested-field/index.scss @@ -0,0 +1,3 @@ +.authn-component__modal .pgn__form-autosuggest__dropdown { + padding: 0 !important; +} diff --git a/dist/forms/fields/email-field/constants.js b/dist/forms/fields/email-field/constants.js new file mode 100644 index 00000000..332379ee --- /dev/null +++ b/dist/forms/fields/email-field/constants.js @@ -0,0 +1,4 @@ +export const COMMON_EMAIL_PROVIDERS = ['hotmail.com', 'yahoo.com', 'outlook.com', 'live.com', 'gmail.com']; +export const DEFAULT_SERVICE_PROVIDER_DOMAINS = ['yahoo', 'hotmail', 'live', 'outlook', 'gmail']; +export const DEFAULT_TOP_LEVEL_DOMAINS = ['aaa', 'aarp', 'abarth', 'abb', 'abbott', 'abbvie', 'abc', 'able', 'abogado', 'abudhabi', 'ac', 'academy', 'accenture', 'accountant', 'accountants', 'aco', 'active', 'actor', 'ad', 'adac', 'ads', 'adult', 'ae', 'aeg', 'aero', 'aetna', 'af', 'afamilycompany', 'afl', 'africa', 'ag', 'agakhan', 'agency', 'ai', 'aig', 'aigo', 'airbus', 'airforce', 'airtel', 'akdn', 'al', 'alfaromeo', 'alibaba', 'alipay', 'allfinanz', 'allstate', 'ally', 'alsace', 'alstom', 'am', 'amazon', 'americanexpress', 'americanfamily', 'amex', 'amfam', 'amica', 'amsterdam', 'an', 'analytics', 'android', 'anquan', 'anz', 'ao', 'aol', 'apartments', 'app', 'apple', 'aq', 'aquarelle', 'ar', 'arab', 'aramco', 'archi', 'army', 'arpa', 'art', 'arte', 'as', 'asda', 'asia', 'associates', 'at', 'athleta', 'attorney', 'au', 'auction', 'audi', 'audible', 'audio', 'auspost', 'author', 'auto', 'autos', 'avianca', 'aw', 'aws', 'ax', 'axa', 'az', 'azure', 'ba', 'baby', 'baidu', 'banamex', 'bananarepublic', 'band', 'bank', 'bar', 'barcelona', 'barclaycard', 'barclays', 'barefoot', 'bargains', 'baseball', 'basketball', 'bauhaus', 'bayern', 'bb', 'bbc', 'bbt', 'bbva', 'bcg', 'bcn', 'bd', 'be', 'beats', 'beauty', 'beer', 'bentley', 'berlin', 'best', 'bestbuy', 'bet', 'bf', 'bg', 'bh', 'bharti', 'bi', 'bible', 'bid', 'bike', 'bing', 'bingo', 'bio', 'biz', 'bj', 'bl', 'black', 'blackfriday', 'blanco', 'blockbuster', 'blog', 'bloomberg', 'blue', 'bm', 'bms', 'bmw', 'bn', 'bnl', 'bnpparibas', 'bo', 'boats', 'boehringer', 'bofa', 'bom', 'bond', 'boo', 'book', 'booking', 'boots', 'bosch', 'bostik', 'boston', 'bot', 'boutique', 'box', 'bq', 'br', 'bradesco', 'bridgestone', 'broadway', 'broker', 'brother', 'brussels', 'bs', 'bt', 'budapest', 'bugatti', 'build', 'builders', 'business', 'buy', 'buzz', 'bv', 'bw', 'by', 'bz', 'bzh', 'ca', 'cab', 'cafe', 'cal', 'call', 'calvinklein', 'cam', 'camera', 'camp', 'cancerresearch', 'canon', 'capetown', 'capital', 'capitalone', 'car', 'caravan', 'cards', 'care', 'career', 'careers', 'cars', 'cartier', 'casa', 'case', 'caseih', 'cash', 'casino', 'cat', 'catering', 'catholic', 'cba', 'cbn', 'cbre', 'cbs', 'cc', 'cd', 'ceb', 'center', 'ceo', 'cern', 'cf', 'cfa', 'cfd', 'cg', 'ch', 'chanel', 'channel', 'charity', 'chase', 'chat', 'cheap', 'chintai', 'chloe', 'christmas', 'chrome', 'chrysler', 'church', 'ci', 'cipriani', 'circle', 'cisco', 'citadel', 'citi', 'citic', 'city', 'cityeats', 'ck', 'cl', 'claims', 'cleaning', 'click', 'clinic', 'clinique', 'clothing', 'cloud', 'club', 'clubmed', 'cm', 'cn', 'co', 'coach', 'codes', 'coffee', 'college', 'cologne', 'com', 'comcast', 'commbank', 'community', 'company', 'compare', 'computer', 'comsec', 'condos', 'construction', 'consulting', 'contact', 'contractors', 'cooking', 'cookingchannel', 'cool', 'coop', 'corsica', 'country', 'coupon', 'coupons', 'courses', 'cpa', 'cr', 'credit', 'creditcard', 'creditunion', 'cricket', 'crown', 'crs', 'cruise', 'cruises', 'csc', 'cu', 'cuisinella', 'cv', 'cw', 'cx', 'cy', 'cymru', 'cyou', 'cz', 'dabur', 'dad', 'dance', 'data', 'date', 'dating', 'datsun', 'day', 'dclk', 'dds', 'de', 'deal', 'dealer', 'deals', 'degree', 'delivery', 'dell', 'deloitte', 'delta', 'democrat', 'dental', 'dentist', 'desi', 'design', 'dev', 'dhl', 'diamonds', 'diet', 'digital', 'direct', 'directory', 'discount', 'discover', 'dish', 'diy', 'dj', 'dk', 'dm', 'dnp', 'do', 'docs', 'doctor', 'dodge', 'dog', 'doha', 'domains', 'doosan', 'dot', 'download', 'drive', 'dtv', 'dubai', 'duck', 'dunlop', 'duns', 'dupont', 'durban', 'dvag', 'dvr', 'dz', 'earth', 'eat', 'ec', 'eco', 'edeka', 'edu', 'education', 'ee', 'eg', 'eh', 'email', 'emerck', 'energy', 'engineer', 'engineering', 'enterprises', 'epost', 'epson', 'equipment', 'er', 'ericsson', 'erni', 'es', 'esq', 'estate', 'esurance', 'et', 'etisalat', 'eu', 'eurovision', 'eus', 'events', 'everbank', 'exchange', 'expert', 'exposed', 'express', 'extraspace', 'fage', 'fail', 'fairwinds', 'faith', 'family', 'fan', 'fans', 'farm', 'farmers', 'fashion', 'fast', 'fedex', 'feedback', 'ferrari', 'ferrero', 'fi', 'fiat', 'fidelity', 'fido', 'film', 'final', 'finance', 'financial', 'fire', 'firestone', 'firmdale', 'fish', 'fishing', 'fit', 'fitness', 'fj', 'fk', 'flickr', 'flights', 'flir', 'florist', 'flowers', 'flsmidth', 'fly', 'fm', 'fo', 'foo', 'food', 'foodnetwork', 'football', 'ford', 'forex', 'forsale', 'forum', 'foundation', 'fox', 'fr', 'free', 'fresenius', 'frl', 'frogans', 'frontdoor', 'frontier', 'ftr', 'fujitsu', 'fujixerox', 'fun', 'fund', 'furniture', 'futbol', 'fyi', 'ga', 'gal', 'gallery', 'gallo', 'gallup', 'game', 'games', 'gap', 'garden', 'gay', 'gb', 'gbiz', 'gd', 'gdn', 'ge', 'gea', 'gent', 'genting', 'george', 'gf', 'gg', 'ggee', 'gh', 'gi', 'gift', 'gifts', 'gives', 'giving', 'gl', 'glade', 'glass', 'gle', 'global', 'globo', 'gm', 'gmail', 'gmbh', 'gmo', 'gmx', 'gn', 'godaddy', 'gold', 'goldpoint', 'golf', 'goo', 'goodhands', 'goodyear', 'goog', 'google', 'gop', 'got', 'gov', 'gp', 'gq', 'gr', 'grainger', 'graphics', 'gratis', 'green', 'gripe', 'grocery', 'group', 'gs', 'gt', 'gu', 'guardian', 'gucci', 'guge', 'guide', 'guitars', 'guru', 'gw', 'gy', 'hair', 'hamburg', 'hangout', 'haus', 'hbo', 'hdfc', 'hdfcbank', 'health', 'healthcare', 'help', 'helsinki', 'here', 'hermes', 'hgtv', 'hiphop', 'hisamitsu', 'hitachi', 'hiv', 'hk', 'hkt', 'hm', 'hn', 'hockey', 'holdings', 'holiday', 'homedepot', 'homegoods', 'homes', 'homesense', 'honda', 'honeywell', 'horse', 'hospital', 'host', 'hosting', 'hot', 'hoteles', 'hotels', 'hotmail', 'house', 'how', 'hr', 'hsbc', 'ht', 'htc', 'hu', 'hughes', 'hyatt', 'hyundai', 'ibm', 'icbc', 'ice', 'icu', 'id', 'ie', 'ieee', 'ifm', 'iinet', 'ikano', 'il', 'im', 'imamat', 'imdb', 'immo', 'immobilien', 'in', 'inc', 'industries', 'infiniti', 'info', 'ing', 'ink', 'institute', 'insurance', 'insure', 'int', 'intel', 'international', 'intuit', 'investments', 'io', 'ipiranga', 'iq', 'ir', 'irish', 'is', 'iselect', 'ismaili', 'ist', 'istanbul', 'it', 'itau', 'itv', 'iveco', 'iwc', 'jaguar', 'java', 'jcb', 'jcp', 'je', 'jeep', 'jetzt', 'jewelry', 'jio', 'jlc', 'jll', 'jm', 'jmp', 'jnj', 'jo', 'jobs', 'joburg', 'jot', 'joy', 'jp', 'jpmorgan', 'jprs', 'juegos', 'juniper', 'kaufen', 'kddi', 'ke', 'kerryhotels', 'kerrylogistics', 'kerryproperties', 'kfh', 'kg', 'kh', 'ki', 'kia', 'kim', 'kinder', 'kindle', 'kitchen', 'kiwi', 'km', 'kn', 'koeln', 'komatsu', 'kosher', 'kp', 'kpmg', 'kpn', 'kr', 'krd', 'kred', 'kuokgroup', 'kw', 'ky', 'kyoto', 'kz', 'la', 'lacaixa', 'ladbrokes', 'lamborghini', 'lamer', 'lancaster', 'lancia', 'lancome', 'land', 'landrover', 'lanxess', 'lasalle', 'lat', 'latino', 'latrobe', 'law', 'lawyer', 'lb', 'lc', 'lds', 'lease', 'leclerc', 'lefrak', 'legal', 'lego', 'lexus', 'lgbt', 'li', 'liaison', 'lidl', 'life', 'lifeinsurance', 'lifestyle', 'lighting', 'like', 'lilly', 'limited', 'limo', 'lincoln', 'linde', 'link', 'lipsy', 'live', 'living', 'lixil', 'lk', 'llc', 'llp', 'loan', 'loans', 'locker', 'locus', 'loft', 'lol', 'london', 'lotte', 'lotto', 'love', 'lpl', 'lplfinancial', 'lr', 'ls', 'lt', 'ltd', 'ltda', 'lu', 'lundbeck', 'lupin', 'luxe', 'luxury', 'lv', 'ly', 'ma', 'macys', 'madrid', 'maif', 'maison', 'makeup', 'man', 'management', 'mango', 'map', 'market', 'marketing', 'markets', 'marriott', 'marshalls', 'maserati', 'mattel', 'mba', 'mc', 'mcd', 'mcdonalds', 'mckinsey', 'md', 'me', 'med', 'media', 'meet', 'melbourne', 'meme', 'memorial', 'men', 'menu', 'meo', 'merckmsd', 'metlife', 'mf', 'mg', 'mh', 'miami', 'microsoft', 'mil', 'mini', 'mint', 'mit', 'mitsubishi', 'mk', 'ml', 'mlb', 'mls', 'mm', 'mma', 'mn', 'mo', 'mobi', 'mobile', 'mobily', 'moda', 'moe', 'moi', 'mom', 'monash', 'money', 'monster', 'montblanc', 'mopar', 'mormon', 'mortgage', 'moscow', 'moto', 'motorcycles', 'mov', 'movie', 'movistar', 'mp', 'mq', 'mr', 'ms', 'msd', 'mt', 'mtn', 'mtpc', 'mtr', 'mu', 'museum', 'mutual', 'mutuelle', 'mv', 'mw', 'mx', 'my', 'mz', 'na', 'nab', 'nadex', 'nagoya', 'name', 'nationwide', 'natura', 'navy', 'nba', 'nc', 'ne', 'nec', 'net', 'netbank', 'netflix', 'network', 'neustar', 'new', 'newholland', 'news', 'next', 'nextdirect', 'nexus', 'nf', 'nfl', 'ng', 'ngo', 'nhk', 'ni', 'nico', 'nike', 'nikon', 'ninja', 'nissan', 'nissay', 'nl', 'no', 'nokia', 'northwesternmutual', 'norton', 'now', 'nowruz', 'nowtv', 'np', 'nr', 'nra', 'nrw', 'ntt', 'nu', 'nyc', 'nz', 'obi', 'observer', 'off', 'office', 'okinawa', 'olayan', 'olayangroup', 'oldnavy', 'ollo', 'om', 'omega', 'one', 'ong', 'onl', 'online', 'onyourside', 'ooo', 'open', 'oracle', 'orange', 'org', 'organic', 'orientexpress', 'origins', 'osaka', 'otsuka', 'ott', 'ovh', 'pa', 'page', 'pamperedchef', 'panasonic', 'panerai', 'paris', 'pars', 'partners', 'parts', 'party', 'passagens', 'pay', 'pccw', 'pe', 'pet', 'pf', 'pfizer', 'pg', 'ph', 'pharmacy', 'phd', 'philips', 'phone', 'photo', 'photography', 'photos', 'physio', 'piaget', 'pics', 'pictet', 'pictures', 'pid', 'pin', 'ping', 'pink', 'pioneer', 'pizza', 'pk', 'pl', 'place', 'play', 'playstation', 'plumbing', 'plus', 'pm', 'pn', 'pnc', 'pohl', 'poker', 'politie', 'porn', 'post', 'pr', 'pramerica', 'praxi', 'press', 'prime', 'pro', 'prod', 'productions', 'prof', 'progressive', 'promo', 'properties', 'property', 'protection', 'pru', 'prudential', 'ps', 'pt', 'pub', 'pw', 'pwc', 'py', 'qa', 'qpon', 'quebec', 'quest', 'qvc', 'racing', 'radio', 'raid', 're', 'read', 'realestate', 'realtor', 'realty', 'recipes', 'red', 'redstone', 'redumbrella', 'rehab', 'reise', 'reisen', 'reit', 'reliance', 'ren', 'rent', 'rentals', 'repair', 'report', 'republican', 'rest', 'restaurant', 'review', 'reviews', 'rexroth', 'rich', 'richardli', 'ricoh', 'rightathome', 'ril', 'rio', 'rip', 'rmit', 'ro', 'rocher', 'rocks', 'rodeo', 'rogers', 'room', 'rs', 'rsvp', 'ru', 'rugby', 'ruhr', 'run', 'rw', 'rwe', 'ryukyu', 'sa', 'saarland', 'safe', 'safety', 'sakura', 'sale', 'salon', 'samsclub', 'samsung', 'sandvik', 'sandvikcoromant', 'sanofi', 'sap', 'sapo', 'sarl', 'sas', 'save', 'saxo', 'sb', 'sbi', 'sbs', 'sc', 'sca', 'scb', 'schaeffler', 'schmidt', 'scholarships', 'school', 'schule', 'schwarz', 'science', 'scjohnson', 'scor', 'scot', 'sd', 'se', 'search', 'seat', 'secure', 'security', 'seek', 'select', 'sener', 'services', 'ses', 'seven', 'sew', 'sex', 'sexy', 'sfr', 'sg', 'sh', 'shangrila', 'sharp', 'shaw', 'shell', 'shia', 'shiksha', 'shoes', 'shop', 'shopping', 'shouji', 'show', 'showtime', 'shriram', 'si', 'silk', 'sina', 'singles', 'site', 'sj', 'sk', 'ski', 'skin', 'sky', 'skype', 'sl', 'sling', 'sm', 'smart', 'smile', 'sn', 'sncf', 'so', 'soccer', 'social', 'softbank', 'software', 'sohu', 'solar', 'solutions', 'song', 'sony', 'soy', 'spa', 'space', 'spiegel', 'sport', 'spot', 'spreadbetting', 'sr', 'srl', 'srt', 'ss', 'st', 'stada', 'staples', 'star', 'starhub', 'statebank', 'statefarm', 'statoil', 'stc', 'stcgroup', 'stockholm', 'storage', 'store', 'stream', 'studio', 'study', 'style', 'su', 'sucks', 'supplies', 'supply', 'support', 'surf', 'surgery', 'suzuki', 'sv', 'swatch', 'swiftcover', 'swiss', 'sx', 'sy', 'sydney', 'symantec', 'systems', 'sz', 'tab', 'taipei', 'talk', 'taobao', 'target', 'tatamotors', 'tatar', 'tattoo', 'tax', 'taxi', 'tc', 'tci', 'td', 'tdk', 'team', 'tech', 'technology', 'tel', 'telecity', 'telefonica', 'temasek', 'tennis', 'teva', 'tf', 'tg', 'th', 'thd', 'theater', 'theatre', 'tiaa', 'tickets', 'tienda', 'tiffany', 'tips', 'tires', 'tirol', 'tj', 'tjmaxx', 'tjx', 'tk', 'tkmaxx', 'tl', 'tm', 'tmall', 'tn', 'to', 'today', 'tokyo', 'tools', 'top', 'toray', 'toshiba', 'total', 'tours', 'town', 'toyota', 'toys', 'tp', 'tr', 'trade', 'trading', 'training', 'travel', 'travelchannel', 'travelers', 'travelersinsurance', 'trust', 'trv', 'tt', 'tube', 'tui', 'tunes', 'tushu', 'tv', 'tvs', 'tw', 'tz', 'ua', 'ubank', 'ubs', 'uconnect', 'ug', 'uk', 'um', 'unicom', 'university', 'uno', 'uol', 'ups', 'us', 'uy', 'uz', 'va', 'vacations', 'vana', 'vanguard', 'vc', 've', 'vegas', 'ventures', 'verisign', 'versicherung', 'vet', 'vg', 'vi', 'viajes', 'video', 'vig', 'viking', 'villas', 'vin', 'vip', 'virgin', 'visa', 'vision', 'vista', 'vistaprint', 'viva', 'vivo', 'vlaanderen', 'vn', 'vodka', 'volkswagen', 'volvo', 'vote', 'voting', 'voto', 'voyage', 'vu', 'vuelos', 'wales', 'walmart', 'walter', 'wang', 'wanggou', 'warman', 'watch', 'watches', 'weather', 'weatherchannel', 'webcam', 'weber', 'website', 'wed', 'wedding', 'weibo', 'weir', 'wf', 'whoswho', 'wien', 'wiki', 'williamhill', 'win', 'windows', 'wine', 'winners', 'wme', 'wolterskluwer', 'woodside', 'work', 'works', 'world', 'wow', 'ws', 'wtc', 'wtf', 'xbox', 'xerox', 'xfinity', 'xihuan', 'xin', '测试', 'कॉम', 'परीक्षा', 'セール', '佛山', 'ಭಾರತ', '慈善', '集团', '在线', '한국', 'ଭାରତ', '大众汽车', '点看', 'คอม', 'ভাৰত', 'ভারত', '八卦', 'ישראל\u200e', 'موقع\u200e', 'বাংলা', '公益', '公司', '香格里拉', '网站', '移动', '我爱你', 'москва', 'испытание', 'қаз', 'католик', 'онлайн', 'сайт', '联通', 'срб', 'бг', 'бел', 'קום\u200e', '时尚', '微博', '테스트', '淡马锡', 'ファッション', 'орг', 'नेट', 'ストア', 'アマゾン', '삼성', 'சிங்கப்பூர்', '商标', '商店', '商城', 'дети', 'мкд', 'טעסט\u200e', 'ею', 'ポイント', '新闻', '工行', '家電', 'كوم\u200e', '中文网', '中信', '中国', '中國', '娱乐', '谷歌', 'భారత్', 'ලංකා', '電訊盈科', '购物', '測試', 'クラウド', 'ભારત', '通販', 'भारतम्', 'भारत', 'भारोत', 'آزمایشی\u200e', 'பரிட்சை', '网店', 'संगठन', '餐厅', '网络', 'ком', 'укр', '香港', '亚马逊', '诺基亚', '食品', 'δοκιμή', '飞利浦', 'إختبار\u200e', '台湾', '台灣', '手表', '手机', 'мон', 'الجزائر\u200e', 'عمان\u200e', 'ارامكو\u200e', 'ایران\u200e', 'العليان\u200e', 'اتصالات\u200e', 'امارات\u200e', 'بازار\u200e', 'موريتانيا\u200e', 'پاکستان\u200e', 'الاردن\u200e', 'موبايلي\u200e', 'بارت\u200e', 'بھارت\u200e', 'المغرب\u200e', 'ابوظبي\u200e', 'البحرين\u200e', 'السعودية\u200e', 'ڀارت\u200e', 'كاثوليك\u200e', 'سودان\u200e', 'همراه\u200e', 'عراق\u200e', 'مليسيا\u200e', '澳門', '닷컴', '政府', 'شبكة\u200e', 'بيتك\u200e', 'عرب\u200e', 'გე', '机构', '组织机构', '健康', 'ไทย', 'سورية\u200e', '招聘', 'рус', 'рф', '珠宝', 'تونس\u200e', '大拿', 'ລາວ', 'みんな', 'グーグル', 'ευ', 'ελ', '世界', '書籍', 'ഭാരതം', 'ਭਾਰਤ', '网址', '닷넷', 'コム', '天主教', '游戏', 'vermögensberater', 'vermögensberatung', '企业', '信息', '嘉里大酒店', '嘉里', 'مصر\u200e', 'قطر\u200e', '广东', 'இலங்கை', 'இந்தியா', 'հայ', '新加坡', 'فلسطين\u200e', 'テスト', '政务', 'xperia', 'xxx', 'xyz', 'yachts', 'yahoo', 'yamaxun', 'yandex', 'ye', 'yodobashi', 'yoga', 'yokohama', 'you', 'youtube', 'yt', 'yun', 'za', 'zappos', 'zara', 'zero', 'zip', 'zippo', 'zm', 'zone', 'zuerich', 'zw']; +//# sourceMappingURL=constants.js.map \ No newline at end of file diff --git a/dist/forms/fields/email-field/constants.js.map b/dist/forms/fields/email-field/constants.js.map new file mode 100644 index 00000000..610cbd8f --- /dev/null +++ b/dist/forms/fields/email-field/constants.js.map @@ -0,0 +1 @@ +{"version":3,"file":"constants.js","names":["COMMON_EMAIL_PROVIDERS","DEFAULT_SERVICE_PROVIDER_DOMAINS","DEFAULT_TOP_LEVEL_DOMAINS"],"sources":["../../../../src/forms/fields/email-field/constants.js"],"sourcesContent":["export const COMMON_EMAIL_PROVIDERS = [\n 'hotmail.com', 'yahoo.com', 'outlook.com', 'live.com', 'gmail.com',\n];\n\nexport const DEFAULT_SERVICE_PROVIDER_DOMAINS = ['yahoo', 'hotmail', 'live', 'outlook', 'gmail'];\n\nexport const DEFAULT_TOP_LEVEL_DOMAINS = [\n 'aaa', 'aarp', 'abarth', 'abb', 'abbott', 'abbvie', 'abc', 'able', 'abogado', 'abudhabi', 'ac', 'academy',\n 'accenture', 'accountant', 'accountants', 'aco', 'active', 'actor', 'ad', 'adac', 'ads', 'adult', 'ae', 'aeg', 'aero',\n 'aetna', 'af', 'afamilycompany', 'afl', 'africa', 'ag', 'agakhan', 'agency', 'ai', 'aig', 'aigo', 'airbus', 'airforce',\n 'airtel', 'akdn', 'al', 'alfaromeo', 'alibaba', 'alipay', 'allfinanz', 'allstate', 'ally', 'alsace', 'alstom', 'am',\n 'amazon', 'americanexpress', 'americanfamily', 'amex', 'amfam', 'amica', 'amsterdam', 'an', 'analytics', 'android',\n 'anquan', 'anz', 'ao', 'aol', 'apartments', 'app', 'apple', 'aq', 'aquarelle', 'ar', 'arab', 'aramco', 'archi', 'army',\n 'arpa', 'art', 'arte', 'as', 'asda', 'asia', 'associates', 'at', 'athleta', 'attorney', 'au', 'auction', 'audi',\n 'audible', 'audio', 'auspost', 'author', 'auto', 'autos', 'avianca', 'aw', 'aws', 'ax', 'axa', 'az', 'azure', 'ba',\n 'baby', 'baidu', 'banamex', 'bananarepublic', 'band', 'bank', 'bar', 'barcelona', 'barclaycard', 'barclays',\n 'barefoot', 'bargains', 'baseball', 'basketball', 'bauhaus', 'bayern', 'bb', 'bbc', 'bbt', 'bbva', 'bcg', 'bcn', 'bd',\n 'be', 'beats', 'beauty', 'beer', 'bentley', 'berlin', 'best', 'bestbuy', 'bet', 'bf', 'bg', 'bh', 'bharti', 'bi',\n 'bible', 'bid', 'bike', 'bing', 'bingo', 'bio', 'biz', 'bj', 'bl', 'black', 'blackfriday', 'blanco', 'blockbuster',\n 'blog', 'bloomberg', 'blue', 'bm', 'bms', 'bmw', 'bn', 'bnl', 'bnpparibas', 'bo', 'boats', 'boehringer', 'bofa', 'bom',\n 'bond', 'boo', 'book', 'booking', 'boots', 'bosch', 'bostik', 'boston', 'bot', 'boutique', 'box', 'bq', 'br',\n 'bradesco', 'bridgestone', 'broadway', 'broker', 'brother', 'brussels', 'bs', 'bt', 'budapest', 'bugatti', 'build',\n 'builders', 'business', 'buy', 'buzz', 'bv', 'bw', 'by', 'bz', 'bzh', 'ca', 'cab', 'cafe', 'cal', 'call',\n 'calvinklein', 'cam', 'camera', 'camp', 'cancerresearch', 'canon', 'capetown', 'capital', 'capitalone', 'car',\n 'caravan', 'cards', 'care', 'career', 'careers', 'cars', 'cartier', 'casa', 'case', 'caseih', 'cash', 'casino', 'cat',\n 'catering', 'catholic', 'cba', 'cbn', 'cbre', 'cbs', 'cc', 'cd', 'ceb', 'center', 'ceo', 'cern', 'cf', 'cfa', 'cfd',\n 'cg', 'ch', 'chanel', 'channel', 'charity', 'chase', 'chat', 'cheap', 'chintai', 'chloe', 'christmas', 'chrome',\n 'chrysler', 'church', 'ci', 'cipriani', 'circle', 'cisco', 'citadel', 'citi', 'citic', 'city', 'cityeats', 'ck', 'cl',\n 'claims', 'cleaning', 'click', 'clinic', 'clinique', 'clothing', 'cloud', 'club', 'clubmed', 'cm', 'cn', 'co', 'coach',\n 'codes', 'coffee', 'college', 'cologne', 'com', 'comcast', 'commbank', 'community', 'company', 'compare', 'computer',\n 'comsec', 'condos', 'construction', 'consulting', 'contact', 'contractors', 'cooking', 'cookingchannel', 'cool', 'coop',\n 'corsica', 'country', 'coupon', 'coupons', 'courses', 'cpa', 'cr', 'credit', 'creditcard', 'creditunion', 'cricket',\n 'crown', 'crs', 'cruise', 'cruises', 'csc', 'cu', 'cuisinella', 'cv', 'cw', 'cx', 'cy', 'cymru', 'cyou', 'cz', 'dabur',\n 'dad', 'dance', 'data', 'date', 'dating', 'datsun', 'day', 'dclk', 'dds', 'de', 'deal', 'dealer', 'deals', 'degree',\n 'delivery', 'dell', 'deloitte', 'delta', 'democrat', 'dental', 'dentist', 'desi', 'design', 'dev', 'dhl', 'diamonds',\n 'diet', 'digital', 'direct', 'directory', 'discount', 'discover', 'dish', 'diy', 'dj', 'dk', 'dm', 'dnp', 'do', 'docs',\n 'doctor', 'dodge', 'dog', 'doha', 'domains', 'doosan', 'dot', 'download', 'drive', 'dtv', 'dubai', 'duck', 'dunlop',\n 'duns', 'dupont', 'durban', 'dvag', 'dvr', 'dz', 'earth', 'eat', 'ec', 'eco', 'edeka', 'edu', 'education', 'ee', 'eg',\n 'eh', 'email', 'emerck', 'energy', 'engineer', 'engineering', 'enterprises', 'epost', 'epson', 'equipment', 'er',\n 'ericsson', 'erni', 'es', 'esq', 'estate', 'esurance', 'et', 'etisalat', 'eu', 'eurovision', 'eus', 'events', 'everbank',\n 'exchange', 'expert', 'exposed', 'express', 'extraspace', 'fage', 'fail', 'fairwinds', 'faith', 'family', 'fan', 'fans',\n 'farm', 'farmers', 'fashion', 'fast', 'fedex', 'feedback', 'ferrari', 'ferrero', 'fi', 'fiat', 'fidelity', 'fido', 'film',\n 'final', 'finance', 'financial', 'fire', 'firestone', 'firmdale', 'fish', 'fishing', 'fit', 'fitness', 'fj', 'fk',\n 'flickr', 'flights', 'flir', 'florist', 'flowers', 'flsmidth', 'fly', 'fm', 'fo', 'foo', 'food', 'foodnetwork', 'football',\n 'ford', 'forex', 'forsale', 'forum', 'foundation', 'fox', 'fr', 'free', 'fresenius', 'frl', 'frogans', 'frontdoor',\n 'frontier', 'ftr', 'fujitsu', 'fujixerox', 'fun', 'fund', 'furniture', 'futbol', 'fyi', 'ga', 'gal', 'gallery', 'gallo',\n 'gallup', 'game', 'games', 'gap', 'garden', 'gay', 'gb', 'gbiz', 'gd', 'gdn', 'ge', 'gea', 'gent', 'genting', 'george',\n 'gf', 'gg', 'ggee', 'gh', 'gi', 'gift', 'gifts', 'gives', 'giving', 'gl', 'glade', 'glass', 'gle', 'global', 'globo',\n 'gm', 'gmail', 'gmbh', 'gmo', 'gmx', 'gn', 'godaddy', 'gold', 'goldpoint', 'golf', 'goo', 'goodhands', 'goodyear', 'goog',\n 'google', 'gop', 'got', 'gov', 'gp', 'gq', 'gr', 'grainger', 'graphics', 'gratis', 'green', 'gripe', 'grocery', 'group',\n 'gs', 'gt', 'gu', 'guardian', 'gucci', 'guge', 'guide', 'guitars', 'guru', 'gw', 'gy', 'hair', 'hamburg', 'hangout',\n 'haus', 'hbo', 'hdfc', 'hdfcbank', 'health', 'healthcare', 'help', 'helsinki', 'here', 'hermes', 'hgtv', 'hiphop',\n 'hisamitsu', 'hitachi', 'hiv', 'hk', 'hkt', 'hm', 'hn', 'hockey', 'holdings', 'holiday', 'homedepot', 'homegoods',\n 'homes', 'homesense', 'honda', 'honeywell', 'horse', 'hospital', 'host', 'hosting', 'hot', 'hoteles', 'hotels', 'hotmail',\n 'house', 'how', 'hr', 'hsbc', 'ht', 'htc', 'hu', 'hughes', 'hyatt', 'hyundai', 'ibm', 'icbc', 'ice', 'icu', 'id', 'ie',\n 'ieee', 'ifm', 'iinet', 'ikano', 'il', 'im', 'imamat', 'imdb', 'immo', 'immobilien', 'in', 'inc', 'industries', 'infiniti',\n 'info', 'ing', 'ink', 'institute', 'insurance', 'insure', 'int', 'intel', 'international', 'intuit', 'investments',\n 'io', 'ipiranga', 'iq', 'ir', 'irish', 'is', 'iselect', 'ismaili', 'ist', 'istanbul', 'it', 'itau', 'itv', 'iveco', 'iwc',\n 'jaguar', 'java', 'jcb', 'jcp', 'je', 'jeep', 'jetzt', 'jewelry', 'jio', 'jlc', 'jll', 'jm', 'jmp', 'jnj', 'jo',\n 'jobs', 'joburg', 'jot', 'joy', 'jp', 'jpmorgan', 'jprs', 'juegos', 'juniper', 'kaufen', 'kddi', 'ke', 'kerryhotels',\n 'kerrylogistics', 'kerryproperties', 'kfh', 'kg', 'kh', 'ki', 'kia', 'kim', 'kinder', 'kindle', 'kitchen', 'kiwi', 'km',\n 'kn', 'koeln', 'komatsu', 'kosher', 'kp', 'kpmg', 'kpn', 'kr', 'krd', 'kred', 'kuokgroup', 'kw', 'ky', 'kyoto', 'kz',\n 'la', 'lacaixa', 'ladbrokes', 'lamborghini', 'lamer', 'lancaster', 'lancia', 'lancome', 'land', 'landrover', 'lanxess',\n 'lasalle', 'lat', 'latino', 'latrobe', 'law', 'lawyer', 'lb', 'lc', 'lds', 'lease', 'leclerc', 'lefrak', 'legal',\n 'lego', 'lexus', 'lgbt', 'li', 'liaison', 'lidl', 'life', 'lifeinsurance', 'lifestyle', 'lighting', 'like', 'lilly',\n 'limited', 'limo', 'lincoln', 'linde', 'link', 'lipsy', 'live', 'living', 'lixil', 'lk', 'llc', 'llp', 'loan', 'loans',\n 'locker', 'locus', 'loft', 'lol', 'london', 'lotte', 'lotto', 'love', 'lpl', 'lplfinancial', 'lr', 'ls', 'lt', 'ltd',\n 'ltda', 'lu', 'lundbeck', 'lupin', 'luxe', 'luxury', 'lv', 'ly', 'ma', 'macys', 'madrid', 'maif', 'maison', 'makeup',\n 'man', 'management', 'mango', 'map', 'market', 'marketing', 'markets', 'marriott', 'marshalls', 'maserati', 'mattel',\n 'mba', 'mc', 'mcd', 'mcdonalds', 'mckinsey', 'md', 'me', 'med', 'media', 'meet', 'melbourne', 'meme', 'memorial', 'men',\n 'menu', 'meo', 'merckmsd', 'metlife', 'mf', 'mg', 'mh', 'miami', 'microsoft', 'mil', 'mini', 'mint', 'mit', 'mitsubishi',\n 'mk', 'ml', 'mlb', 'mls', 'mm', 'mma', 'mn', 'mo', 'mobi', 'mobile', 'mobily', 'moda', 'moe', 'moi', 'mom', 'monash',\n 'money', 'monster', 'montblanc', 'mopar', 'mormon', 'mortgage', 'moscow', 'moto', 'motorcycles', 'mov', 'movie', 'movistar',\n 'mp', 'mq', 'mr', 'ms', 'msd', 'mt', 'mtn', 'mtpc', 'mtr', 'mu', 'museum', 'mutual', 'mutuelle', 'mv', 'mw', 'mx', 'my',\n 'mz', 'na', 'nab', 'nadex', 'nagoya', 'name', 'nationwide', 'natura', 'navy', 'nba', 'nc', 'ne', 'nec', 'net', 'netbank',\n 'netflix', 'network', 'neustar', 'new', 'newholland', 'news', 'next', 'nextdirect', 'nexus', 'nf', 'nfl', 'ng', 'ngo', 'nhk',\n 'ni', 'nico', 'nike', 'nikon', 'ninja', 'nissan', 'nissay', 'nl', 'no', 'nokia', 'northwesternmutual', 'norton', 'now',\n 'nowruz', 'nowtv', 'np', 'nr', 'nra', 'nrw', 'ntt', 'nu', 'nyc', 'nz', 'obi', 'observer', 'off', 'office', 'okinawa',\n 'olayan', 'olayangroup', 'oldnavy', 'ollo', 'om', 'omega', 'one', 'ong', 'onl', 'online', 'onyourside', 'ooo', 'open',\n 'oracle', 'orange', 'org', 'organic', 'orientexpress', 'origins', 'osaka', 'otsuka', 'ott', 'ovh', 'pa', 'page',\n 'pamperedchef', 'panasonic', 'panerai', 'paris', 'pars', 'partners', 'parts', 'party', 'passagens', 'pay', 'pccw', 'pe',\n 'pet', 'pf', 'pfizer', 'pg', 'ph', 'pharmacy', 'phd', 'philips', 'phone', 'photo', 'photography', 'photos', 'physio',\n 'piaget', 'pics', 'pictet', 'pictures', 'pid', 'pin', 'ping', 'pink', 'pioneer', 'pizza', 'pk', 'pl', 'place', 'play',\n 'playstation', 'plumbing', 'plus', 'pm', 'pn', 'pnc', 'pohl', 'poker', 'politie', 'porn', 'post', 'pr', 'pramerica',\n 'praxi', 'press', 'prime', 'pro', 'prod', 'productions', 'prof', 'progressive', 'promo', 'properties', 'property',\n 'protection', 'pru', 'prudential', 'ps', 'pt', 'pub', 'pw', 'pwc', 'py', 'qa', 'qpon', 'quebec', 'quest', 'qvc',\n 'racing', 'radio', 'raid', 're', 'read', 'realestate', 'realtor', 'realty', 'recipes', 'red', 'redstone', 'redumbrella',\n 'rehab', 'reise', 'reisen', 'reit', 'reliance', 'ren', 'rent', 'rentals', 'repair', 'report', 'republican', 'rest',\n 'restaurant', 'review', 'reviews', 'rexroth', 'rich', 'richardli', 'ricoh', 'rightathome', 'ril', 'rio', 'rip', 'rmit',\n 'ro', 'rocher', 'rocks', 'rodeo', 'rogers', 'room', 'rs', 'rsvp', 'ru', 'rugby', 'ruhr', 'run', 'rw', 'rwe', 'ryukyu',\n 'sa', 'saarland', 'safe', 'safety', 'sakura', 'sale', 'salon', 'samsclub', 'samsung', 'sandvik', 'sandvikcoromant',\n 'sanofi', 'sap', 'sapo', 'sarl', 'sas', 'save', 'saxo', 'sb', 'sbi', 'sbs', 'sc', 'sca', 'scb', 'schaeffler', 'schmidt',\n 'scholarships', 'school', 'schule', 'schwarz', 'science', 'scjohnson', 'scor', 'scot', 'sd', 'se', 'search', 'seat',\n 'secure', 'security', 'seek', 'select', 'sener', 'services', 'ses', 'seven', 'sew', 'sex', 'sexy', 'sfr', 'sg', 'sh',\n 'shangrila', 'sharp', 'shaw', 'shell', 'shia', 'shiksha', 'shoes', 'shop', 'shopping', 'shouji', 'show', 'showtime',\n 'shriram', 'si', 'silk', 'sina', 'singles', 'site', 'sj', 'sk', 'ski', 'skin', 'sky', 'skype', 'sl', 'sling', 'sm',\n 'smart', 'smile', 'sn', 'sncf', 'so', 'soccer', 'social', 'softbank', 'software', 'sohu', 'solar', 'solutions', 'song',\n 'sony', 'soy', 'spa', 'space', 'spiegel', 'sport', 'spot', 'spreadbetting', 'sr', 'srl', 'srt', 'ss', 'st', 'stada',\n 'staples', 'star', 'starhub', 'statebank', 'statefarm', 'statoil', 'stc', 'stcgroup', 'stockholm', 'storage', 'store',\n 'stream', 'studio', 'study', 'style', 'su', 'sucks', 'supplies', 'supply', 'support', 'surf', 'surgery', 'suzuki', 'sv',\n 'swatch', 'swiftcover', 'swiss', 'sx', 'sy', 'sydney', 'symantec', 'systems', 'sz', 'tab', 'taipei', 'talk', 'taobao',\n 'target', 'tatamotors', 'tatar', 'tattoo', 'tax', 'taxi', 'tc', 'tci', 'td', 'tdk', 'team', 'tech', 'technology', 'tel',\n 'telecity', 'telefonica', 'temasek', 'tennis', 'teva', 'tf', 'tg', 'th', 'thd', 'theater', 'theatre', 'tiaa', 'tickets',\n 'tienda', 'tiffany', 'tips', 'tires', 'tirol', 'tj', 'tjmaxx', 'tjx', 'tk', 'tkmaxx', 'tl', 'tm', 'tmall', 'tn', 'to',\n 'today', 'tokyo', 'tools', 'top', 'toray', 'toshiba', 'total', 'tours', 'town', 'toyota', 'toys', 'tp', 'tr', 'trade',\n 'trading', 'training', 'travel', 'travelchannel', 'travelers', 'travelersinsurance', 'trust', 'trv', 'tt', 'tube', 'tui',\n 'tunes', 'tushu', 'tv', 'tvs', 'tw', 'tz', 'ua', 'ubank', 'ubs', 'uconnect', 'ug', 'uk', 'um', 'unicom', 'university',\n 'uno', 'uol', 'ups', 'us', 'uy', 'uz', 'va', 'vacations', 'vana', 'vanguard', 'vc', 've', 'vegas', 'ventures', 'verisign',\n 'versicherung', 'vet', 'vg', 'vi', 'viajes', 'video', 'vig', 'viking', 'villas', 'vin', 'vip', 'virgin', 'visa', 'vision',\n 'vista', 'vistaprint', 'viva', 'vivo', 'vlaanderen', 'vn', 'vodka', 'volkswagen', 'volvo', 'vote', 'voting', 'voto',\n 'voyage', 'vu', 'vuelos', 'wales', 'walmart', 'walter', 'wang', 'wanggou', 'warman', 'watch', 'watches', 'weather',\n 'weatherchannel', 'webcam', 'weber', 'website', 'wed', 'wedding', 'weibo', 'weir', 'wf', 'whoswho', 'wien', 'wiki',\n 'williamhill', 'win', 'windows', 'wine', 'winners', 'wme', 'wolterskluwer', 'woodside', 'work', 'works', 'world', 'wow',\n 'ws', 'wtc', 'wtf', 'xbox', 'xerox', 'xfinity', 'xihuan', 'xin', '测试', 'कॉम', 'परीक्षा', 'セール', '佛山', 'ಭಾರತ', '慈善',\n '集团', '在线', '한국', 'ଭାରତ', '大众汽车', '点看', 'คอม', 'ভাৰত', 'ভারত', '八卦', 'ישראל\\u200e', 'موقع\\u200e', 'বাংলা', '公益',\n '公司', '香格里拉', '网站', '移动', '我爱你', 'москва', 'испытание', 'қаз', 'католик', 'онлайн', 'сайт', '联通', 'срб', 'бг',\n 'бел', 'קום\\u200e', '时尚', '微博', '테스트', '淡马锡', 'ファッション', 'орг', 'नेट', 'ストア', 'アマゾン', '삼성', 'சிங்கப்பூர்', '商标',\n '商店', '商城', 'дети', 'мкд', 'טעסט\\u200e', 'ею', 'ポイント', '新闻', '工行', '家電', 'كوم\\u200e', '中文网', '中信', '中国',\n '中國', '娱乐', '谷歌', 'భారత్', 'ලංකා', '電訊盈科', '购物', '測試', 'クラウド', 'ભારત', '通販', 'भारतम्', 'भारत', 'भारोत', 'آزمایشی\\u200e',\n 'பரிட்சை', '网店', 'संगठन', '餐厅', '网络', 'ком', 'укр', '香港', '亚马逊', '诺基亚', '食品', 'δοκιμή', '飞利浦', 'إختبار\\u200e',\n '台湾', '台灣', '手表', '手机', 'мон', 'الجزائر\\u200e', 'عمان\\u200e', 'ارامكو\\u200e', 'ایران\\u200e', 'العليان\\u200e',\n 'اتصالات\\u200e', 'امارات\\u200e', 'بازار\\u200e', 'موريتانيا\\u200e', 'پاکستان\\u200e', 'الاردن\\u200e', 'موبايلي\\u200e',\n 'بارت\\u200e', 'بھارت\\u200e', 'المغرب\\u200e', 'ابوظبي\\u200e', 'البحرين\\u200e', 'السعودية\\u200e', 'ڀارت\\u200e',\n 'كاثوليك\\u200e', 'سودان\\u200e', 'همراه\\u200e', 'عراق\\u200e', 'مليسيا\\u200e', '澳門', '닷컴', '政府', 'شبكة\\u200e',\n 'بيتك\\u200e', 'عرب\\u200e', 'გე', '机构', '组织机构', '健康', 'ไทย', 'سورية\\u200e', '招聘', 'рус', 'рф', '珠宝',\n 'تونس\\u200e', '大拿', 'ລາວ', 'みんな', 'グーグル', 'ευ', 'ελ', '世界', '書籍', 'ഭാരതം', 'ਭਾਰਤ', '网址', '닷넷', 'コム',\n '天主教', '游戏', 'vermögensberater', 'vermögensberatung', '企业', '信息', '嘉里大酒店', '嘉里', 'مصر\\u200e',\n 'قطر\\u200e', '广东', 'இலங்கை', 'இந்தியா', 'հայ', '新加坡', 'فلسطين\\u200e', 'テスト', '政务', 'xperia', 'xxx',\n 'xyz', 'yachts', 'yahoo', 'yamaxun', 'yandex', 'ye', 'yodobashi', 'yoga', 'yokohama', 'you', 'youtube', 'yt',\n 'yun', 'za', 'zappos', 'zara', 'zero', 'zip', 'zippo', 'zm', 'zone', 'zuerich', 'zw',\n];\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/fields/email-field/index.js b/dist/forms/fields/email-field/index.js new file mode 100644 index 00000000..9f00fb8f --- /dev/null +++ b/dist/forms/fields/email-field/index.js @@ -0,0 +1,137 @@ +import React, { forwardRef, useState } from 'react'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Alert, Form, Icon } from '@openedx/paragon'; +import { Close, Error } from '@openedx/paragon/icons'; +import classNames from 'classnames'; +import PropTypes from 'prop-types'; +import messages from './messages'; +import validateEmail from './validator'; +import { useDispatch, useSelector } from '../../../data/storeHooks'; +import { clearRegistrationBackendError, fetchRealtimeValidations } from '../../registration-popup/data/reducers'; +import getValidationMessage from '../../reset-password-popup/forgot-password/data/utils'; +import './index.scss'; +const EmailField = /*#__PURE__*/forwardRef((props, ref) => { + const dispatch = useDispatch(); + const { + formatMessage + } = useIntl(); + const { + name, + value, + isRegistration = true, + handleChange, + floatingLabel, + errorMessage = '', + handleErrorChange = () => {}, + validateEmailFromBackend = true + } = props; + const validationApiRateLimited = useSelector(state => state.register?.validationApiRateLimited); + const [emailSuggestion, setEmailSuggestion] = useState({}); + const handleOnBlur = e => { + const { + value: fieldValue + } = e.target; + if (isRegistration) { + const { + fieldError, + suggestion + } = validateEmail(fieldValue, formatMessage); + setEmailSuggestion(suggestion); + if (fieldError) { + handleErrorChange('email', fieldError); + } else if (!validationApiRateLimited && validateEmailFromBackend) { + dispatch(fetchRealtimeValidations({ + email: fieldValue + })); + } + } else { + const error = getValidationMessage(fieldValue, formatMessage); + handleErrorChange('email', error); + } + }; + const handleOnFocus = () => { + handleErrorChange('email', ''); + dispatch(clearRegistrationBackendError('email')); + }; + const handleSuggestionClick = event => { + event.preventDefault(); + handleErrorChange('email', ''); + handleChange({ + target: { + name: 'email', + value: emailSuggestion.suggestion + } + }); + setEmailSuggestion({ + suggestion: '', + type: '' + }); + }; + const handleSuggestionClosed = () => setEmailSuggestion({ + suggestion: '', + type: '' + }); + const renderEmailFeedback = () => { + if (emailSuggestion.type === 'error') { + return /*#__PURE__*/React.createElement(Alert, { + variant: "danger", + className: "email-suggestion-alert-error mt-1", + icon: Error + }, /*#__PURE__*/React.createElement("span", { + className: "email-suggestion__text" + }, formatMessage(messages.didYouMeanAlertText), ' ', /*#__PURE__*/React.createElement(Alert.Link, { + href: "#", + name: "email", + onClick: handleSuggestionClick + }, emailSuggestion.suggestion), "?", /*#__PURE__*/React.createElement(Icon, { + src: Close, + className: "email-suggestion__close", + onClick: handleSuggestionClosed, + tabIndex: "0" + }))); + } + return /*#__PURE__*/React.createElement("span", { + id: "email-warning", + className: "small" + }, formatMessage(messages.didYouMeanAlertText), ":", ' ', /*#__PURE__*/React.createElement(Alert.Link, { + href: "#", + name: "email", + className: "email-suggestion-alert-warning", + onClick: handleSuggestionClick + }, emailSuggestion.suggestion), "?"); + }; + return /*#__PURE__*/React.createElement(Form.Group, { + controlId: "email", + className: "w-100 mb-4" + }, /*#__PURE__*/React.createElement(Form.Control, { + className: classNames('mr-0', { + 'yellow-border': emailSuggestion.type === 'warning' && isRegistration + }), + type: "email", + name: name, + value: value, + onChange: handleChange, + onBlur: handleOnBlur, + onFocus: handleOnFocus, + floatingLabel: floatingLabel, + ref: ref + }), errorMessage !== '' && /*#__PURE__*/React.createElement(Form.Control.Feedback, { + key: "error", + className: "form-text-size validation-error-margin", + hasIcon: false, + "feedback-for": props.name, + type: "invalid" + }, errorMessage), emailSuggestion.suggestion && isRegistration ? renderEmailFeedback() : null); +}); +EmailField.propTypes = { + name: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, + handleChange: PropTypes.func.isRequired, + handleErrorChange: PropTypes.func, + floatingLabel: PropTypes.string.isRequired, + errorMessage: PropTypes.string, + isRegistration: PropTypes.bool, + validateEmailFromBackend: PropTypes.bool +}; +export default EmailField; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/forms/fields/email-field/index.js.map b/dist/forms/fields/email-field/index.js.map new file mode 100644 index 00000000..3ab4162e --- /dev/null +++ b/dist/forms/fields/email-field/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["React","forwardRef","useState","useIntl","Alert","Form","Icon","Close","Error","classNames","PropTypes","messages","validateEmail","useDispatch","useSelector","clearRegistrationBackendError","fetchRealtimeValidations","getValidationMessage","EmailField","props","ref","dispatch","formatMessage","name","value","isRegistration","handleChange","floatingLabel","errorMessage","handleErrorChange","validateEmailFromBackend","validationApiRateLimited","state","register","emailSuggestion","setEmailSuggestion","handleOnBlur","e","fieldValue","target","fieldError","suggestion","email","error","handleOnFocus","handleSuggestionClick","event","preventDefault","type","handleSuggestionClosed","renderEmailFeedback","createElement","variant","className","icon","didYouMeanAlertText","Link","href","onClick","src","tabIndex","id","Group","controlId","Control","onChange","onBlur","onFocus","Feedback","key","hasIcon","propTypes","string","isRequired","func","bool"],"sources":["../../../../src/forms/fields/email-field/index.jsx"],"sourcesContent":["import React, { forwardRef, useState } from 'react';\n\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport { Alert, Form, Icon } from '@openedx/paragon';\nimport { Close, Error } from '@openedx/paragon/icons';\nimport classNames from 'classnames';\nimport PropTypes from 'prop-types';\n\nimport messages from './messages';\nimport validateEmail from './validator';\nimport { useDispatch, useSelector } from '../../../data/storeHooks';\nimport { clearRegistrationBackendError, fetchRealtimeValidations } from '../../registration-popup/data/reducers';\nimport getValidationMessage from '../../reset-password-popup/forgot-password/data/utils';\n\nimport './index.scss';\n\nconst EmailField = forwardRef((props, ref) => {\n const dispatch = useDispatch();\n const { formatMessage } = useIntl();\n const {\n name,\n value,\n isRegistration = true,\n handleChange,\n floatingLabel,\n errorMessage = '',\n handleErrorChange = () => {},\n validateEmailFromBackend = true,\n } = props;\n\n const validationApiRateLimited = useSelector(state => state.register?.validationApiRateLimited);\n\n const [emailSuggestion, setEmailSuggestion] = useState({});\n\n const handleOnBlur = (e) => {\n const { value: fieldValue } = e.target;\n if (isRegistration) {\n const { fieldError, suggestion } = validateEmail(fieldValue, formatMessage);\n\n setEmailSuggestion(suggestion);\n\n if (fieldError) {\n handleErrorChange('email', fieldError);\n } else if (!validationApiRateLimited && validateEmailFromBackend) {\n dispatch(fetchRealtimeValidations({ email: fieldValue }));\n }\n } else {\n const error = getValidationMessage(fieldValue, formatMessage);\n handleErrorChange('email', error);\n }\n };\n\n const handleOnFocus = () => {\n handleErrorChange('email', '');\n dispatch(clearRegistrationBackendError('email'));\n };\n\n const handleSuggestionClick = (event) => {\n event.preventDefault();\n handleErrorChange('email', '');\n handleChange({ target: { name: 'email', value: emailSuggestion.suggestion } });\n setEmailSuggestion({ suggestion: '', type: '' });\n };\n\n const handleSuggestionClosed = () => setEmailSuggestion({ suggestion: '', type: '' });\n\n const renderEmailFeedback = () => {\n if (emailSuggestion.type === 'error') {\n return (\n \n \n {formatMessage(messages.didYouMeanAlertText)}{' '}\n \n {emailSuggestion.suggestion}\n ?\n \n \n \n );\n }\n return (\n \n {formatMessage(messages.didYouMeanAlertText)}:{' '}\n \n {emailSuggestion.suggestion}\n ?\n \n );\n };\n\n return (\n \n \n\n {errorMessage !== '' && (\n \n {errorMessage}\n \n )}\n {emailSuggestion.suggestion && isRegistration ? renderEmailFeedback() : null}\n \n );\n});\n\nEmailField.propTypes = {\n name: PropTypes.string.isRequired,\n value: PropTypes.string.isRequired,\n handleChange: PropTypes.func.isRequired,\n handleErrorChange: PropTypes.func,\n floatingLabel: PropTypes.string.isRequired,\n errorMessage: PropTypes.string,\n isRegistration: PropTypes.bool,\n validateEmailFromBackend: PropTypes.bool,\n};\n\nexport default EmailField;\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/fields/email-field/index.scss b/dist/forms/fields/email-field/index.scss new file mode 100644 index 00000000..04310d55 --- /dev/null +++ b/dist/forms/fields/email-field/index.scss @@ -0,0 +1,35 @@ +@import "~@edx/brand-edx.org/paragon/variables"; + +.email-suggestion-alert-error { + padding: 0.5rem 1rem !important; + + .email-suggestion__close { + float: right !important; + + &:hover { + cursor: pointer !important; + } + } + + .email-suggestion__text { + font-size: 0.75rem !important; + line-height: 1.25rem !important; + } + + .alert-link { + color: $primary !important; + + &:hover { + text-decoration: underline !important; + color: $info-700 !important; + } + } +} + +.validation-error-margin { + margin-top: 10px !important; +} + +.yellow-border { + border: 2px solid $accent-b !important; +} diff --git a/dist/forms/fields/email-field/messages.js b/dist/forms/fields/email-field/messages.js new file mode 100644 index 00000000..b6cce5d3 --- /dev/null +++ b/dist/forms/fields/email-field/messages.js @@ -0,0 +1,20 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; +const messages = defineMessages({ + didYouMeanAlertText: { + id: 'did.you.mean.alert.text', + defaultMessage: 'Did you mean', + description: 'Did you mean alert suggestion' + }, + emptyEmailFieldError: { + id: 'empty.email.field.error', + defaultMessage: 'Email is required', + description: 'Error message for empty email field' + }, + emailInvalidFormaterror: { + id: 'email.invalid.format.error', + defaultMessage: 'Enter a valid email address', + description: 'Validation error for invalid email address' + } +}); +export default messages; +//# sourceMappingURL=messages.js.map \ No newline at end of file diff --git a/dist/forms/fields/email-field/messages.js.map b/dist/forms/fields/email-field/messages.js.map new file mode 100644 index 00000000..82a3ac1f --- /dev/null +++ b/dist/forms/fields/email-field/messages.js.map @@ -0,0 +1 @@ +{"version":3,"file":"messages.js","names":["defineMessages","messages","didYouMeanAlertText","id","defaultMessage","description","emptyEmailFieldError","emailInvalidFormaterror"],"sources":["../../../../src/forms/fields/email-field/messages.jsx"],"sourcesContent":["import { defineMessages } from '@edx/frontend-platform/i18n';\n\nconst messages = defineMessages({\n didYouMeanAlertText: {\n id: 'did.you.mean.alert.text',\n defaultMessage: 'Did you mean',\n description: 'Did you mean alert suggestion',\n },\n emptyEmailFieldError: {\n id: 'empty.email.field.error',\n defaultMessage: 'Email is required',\n description: 'Error message for empty email field',\n },\n emailInvalidFormaterror: {\n id: 'email.invalid.format.error',\n defaultMessage: 'Enter a valid email address',\n description: 'Validation error for invalid email address',\n },\n});\n\nexport default messages;\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,6BAA6B;AAE5D,MAAMC,QAAQ,GAAGD,cAAc,CAAC;EAC9BE,mBAAmB,EAAE;IACnBC,EAAE,EAAE,yBAAyB;IAC7BC,cAAc,EAAE,cAAc;IAC9BC,WAAW,EAAE;EACf,CAAC;EACDC,oBAAoB,EAAE;IACpBH,EAAE,EAAE,yBAAyB;IAC7BC,cAAc,EAAE,mBAAmB;IACnCC,WAAW,EAAE;EACf,CAAC;EACDE,uBAAuB,EAAE;IACvBJ,EAAE,EAAE,4BAA4B;IAChCC,cAAc,EAAE,6BAA6B;IAC7CC,WAAW,EAAE;EACf;AACF,CAAC,CAAC;AAEF,eAAeJ,QAAQ","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/fields/email-field/validator.js b/dist/forms/fields/email-field/validator.js new file mode 100644 index 00000000..80dfd1fc --- /dev/null +++ b/dist/forms/fields/email-field/validator.js @@ -0,0 +1,110 @@ +function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } +function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } +function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); } +function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } +import { distance } from 'fastest-levenshtein'; +import { COMMON_EMAIL_PROVIDERS, DEFAULT_SERVICE_PROVIDER_DOMAINS, DEFAULT_TOP_LEVEL_DOMAINS } from './constants'; +import messages from './messages'; +import { VALID_EMAIL_REGEX } from '../../registration-popup/data/constants'; +export const emailRegex = new RegExp(VALID_EMAIL_REGEX, 'i'); +export const getLevenshteinSuggestion = function (word, knownWords) { + let similarityThreshold = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 4; + if (!word) { + return null; + } + let minEditDistance = 100; + let mostSimilar = word; + for (let i = 0; i < knownWords.length; i++) { + const editDistance = distance(knownWords[i].toLowerCase(), word.toLowerCase()); + if (editDistance < minEditDistance) { + minEditDistance = editDistance; + mostSimilar = knownWords[i]; + } + } + return minEditDistance <= similarityThreshold && word !== mostSimilar ? mostSimilar : null; +}; +export const getSuggestionForInvalidEmail = (domain, username) => { + if (!domain) { + return ''; + } + const defaultDomains = ['yahoo', 'aol', 'hotmail', 'live', 'outlook', 'gmail']; + const suggestion = getLevenshteinSuggestion(domain, COMMON_EMAIL_PROVIDERS); + if (suggestion) { + return `${username}@${suggestion}`; + } + for (let i = 0; i < defaultDomains.length; i++) { + if (domain.includes(defaultDomains[i])) { + return `${username}@${defaultDomains[i]}.com`; + } + } + return ''; +}; +export const validateEmailAddress = (value, username, domainName) => { + let suggestion = null; + const validation = { + hasError: false, + suggestion: '', + type: '' + }; + const hasMultipleSubdomains = value.match(/\./g).length > 1; + const [serviceLevelDomain, topLevelDomain] = domainName.split('.'); + const tldSuggestion = !DEFAULT_TOP_LEVEL_DOMAINS.includes(topLevelDomain); + const serviceSuggestion = getLevenshteinSuggestion(serviceLevelDomain, DEFAULT_SERVICE_PROVIDER_DOMAINS, 2); + if (DEFAULT_SERVICE_PROVIDER_DOMAINS.includes(serviceSuggestion || serviceLevelDomain)) { + suggestion = `${username}@${serviceSuggestion || serviceLevelDomain}.com`; + } + if (!hasMultipleSubdomains && tldSuggestion) { + validation.suggestion = suggestion; + validation.type = 'error'; + } else if (serviceSuggestion) { + validation.suggestion = suggestion; + validation.type = 'warning'; + } else { + suggestion = getLevenshteinSuggestion(domainName, COMMON_EMAIL_PROVIDERS, 3); + if (suggestion) { + validation.suggestion = `${username}@${suggestion}`; + validation.type = 'warning'; + } + } + if (!hasMultipleSubdomains && tldSuggestion) { + validation.hasError = true; + } + return validation; +}; +const validateEmail = (value, formatMessage) => { + let fieldError = ''; + let emailSuggestion = { + suggestion: '', + type: '' + }; + if (!value) { + fieldError = formatMessage(messages.emptyEmailFieldError); + } else if (value.length <= 2) { + fieldError = formatMessage(messages.emailInvalidFormaterror); + } else { + const [username, domainName] = value.split('@'); + // Check if email address is invalid. If we have a suggestion for invalid email + // provide that along with the error message. + if (!emailRegex.test(value)) { + fieldError = formatMessage(messages.emailInvalidFormaterror); + emailSuggestion = { + suggestion: getSuggestionForInvalidEmail(domainName, username), + type: 'error' + }; + } else { + const response = validateEmailAddress(value, username, domainName); + if (response.hasError) { + fieldError = formatMessage(messages.emailInvalidFormaterror); + delete response.hasError; + } + emailSuggestion = _objectSpread({}, response); + } + } + return { + fieldError, + suggestion: emailSuggestion + }; +}; +export default validateEmail; +//# sourceMappingURL=validator.js.map \ No newline at end of file diff --git a/dist/forms/fields/email-field/validator.js.map b/dist/forms/fields/email-field/validator.js.map new file mode 100644 index 00000000..a3095b70 --- /dev/null +++ b/dist/forms/fields/email-field/validator.js.map @@ -0,0 +1 @@ +{"version":3,"file":"validator.js","names":["distance","COMMON_EMAIL_PROVIDERS","DEFAULT_SERVICE_PROVIDER_DOMAINS","DEFAULT_TOP_LEVEL_DOMAINS","messages","VALID_EMAIL_REGEX","emailRegex","RegExp","getLevenshteinSuggestion","word","knownWords","similarityThreshold","arguments","length","undefined","minEditDistance","mostSimilar","i","editDistance","toLowerCase","getSuggestionForInvalidEmail","domain","username","defaultDomains","suggestion","includes","validateEmailAddress","value","domainName","validation","hasError","type","hasMultipleSubdomains","match","serviceLevelDomain","topLevelDomain","split","tldSuggestion","serviceSuggestion","validateEmail","formatMessage","fieldError","emailSuggestion","emptyEmailFieldError","emailInvalidFormaterror","test","response","_objectSpread"],"sources":["../../../../src/forms/fields/email-field/validator.js"],"sourcesContent":["import { distance } from 'fastest-levenshtein';\n\nimport {\n COMMON_EMAIL_PROVIDERS,\n DEFAULT_SERVICE_PROVIDER_DOMAINS,\n DEFAULT_TOP_LEVEL_DOMAINS,\n} from './constants';\nimport messages from './messages';\nimport { VALID_EMAIL_REGEX } from '../../registration-popup/data/constants';\n\nexport const emailRegex = new RegExp(VALID_EMAIL_REGEX, 'i');\n\nexport const getLevenshteinSuggestion = (word, knownWords, similarityThreshold = 4) => {\n if (!word) {\n return null;\n }\n\n let minEditDistance = 100;\n let mostSimilar = word;\n\n for (let i = 0; i < knownWords.length; i++) {\n const editDistance = distance(knownWords[i].toLowerCase(), word.toLowerCase());\n if (editDistance < minEditDistance) {\n minEditDistance = editDistance;\n mostSimilar = knownWords[i];\n }\n }\n\n return minEditDistance <= similarityThreshold && word !== mostSimilar ? mostSimilar : null;\n};\n\nexport const getSuggestionForInvalidEmail = (domain, username) => {\n if (!domain) {\n return '';\n }\n\n const defaultDomains = ['yahoo', 'aol', 'hotmail', 'live', 'outlook', 'gmail'];\n const suggestion = getLevenshteinSuggestion(domain, COMMON_EMAIL_PROVIDERS);\n\n if (suggestion) {\n return `${username}@${suggestion}`;\n }\n\n for (let i = 0; i < defaultDomains.length; i++) {\n if (domain.includes(defaultDomains[i])) {\n return `${username}@${defaultDomains[i]}.com`;\n }\n }\n\n return '';\n};\n\nexport const validateEmailAddress = (value, username, domainName) => {\n let suggestion = null;\n const validation = {\n hasError: false,\n suggestion: '',\n type: '',\n };\n\n const hasMultipleSubdomains = value.match(/\\./g).length > 1;\n const [serviceLevelDomain, topLevelDomain] = domainName.split('.');\n const tldSuggestion = !DEFAULT_TOP_LEVEL_DOMAINS.includes(topLevelDomain);\n const serviceSuggestion = getLevenshteinSuggestion(serviceLevelDomain, DEFAULT_SERVICE_PROVIDER_DOMAINS, 2);\n\n if (DEFAULT_SERVICE_PROVIDER_DOMAINS.includes(serviceSuggestion || serviceLevelDomain)) {\n suggestion = `${username}@${serviceSuggestion || serviceLevelDomain}.com`;\n }\n\n if (!hasMultipleSubdomains && tldSuggestion) {\n validation.suggestion = suggestion;\n validation.type = 'error';\n } else if (serviceSuggestion) {\n validation.suggestion = suggestion;\n validation.type = 'warning';\n } else {\n suggestion = getLevenshteinSuggestion(domainName, COMMON_EMAIL_PROVIDERS, 3);\n if (suggestion) {\n validation.suggestion = `${username}@${suggestion}`;\n validation.type = 'warning';\n }\n }\n\n if (!hasMultipleSubdomains && tldSuggestion) {\n validation.hasError = true;\n }\n\n return validation;\n};\n\nconst validateEmail = (value, formatMessage) => {\n let fieldError = '';\n let emailSuggestion = { suggestion: '', type: '' };\n\n if (!value) {\n fieldError = formatMessage(messages.emptyEmailFieldError);\n } else if (value.length <= 2) {\n fieldError = formatMessage(messages.emailInvalidFormaterror);\n } else {\n const [username, domainName] = value.split('@');\n // Check if email address is invalid. If we have a suggestion for invalid email\n // provide that along with the error message.\n if (!emailRegex.test(value)) {\n fieldError = formatMessage(messages.emailInvalidFormaterror);\n emailSuggestion = {\n suggestion: getSuggestionForInvalidEmail(domainName, username),\n type: 'error',\n };\n } else {\n const response = validateEmailAddress(value, username, domainName);\n if (response.hasError) {\n fieldError = formatMessage(messages.emailInvalidFormaterror);\n delete response.hasError;\n }\n emailSuggestion = { ...response };\n }\n }\n return { fieldError, suggestion: emailSuggestion };\n};\n\nexport default validateEmail;\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/fields/index.js b/dist/forms/fields/index.js new file mode 100644 index 00000000..92b3071b --- /dev/null +++ b/dist/forms/fields/index.js @@ -0,0 +1,6 @@ +export { default as EmailField } from './email-field'; +export { default as PasswordField } from './password-field'; +export { default as TextField } from './text-field'; +export { default as NameField } from './name-field'; +export { default as MarketingEmailOptInCheckbox } from './marketing-email-opt-out-field'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/forms/fields/index.js.map b/dist/forms/fields/index.js.map new file mode 100644 index 00000000..b8dcbd4c --- /dev/null +++ b/dist/forms/fields/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["default","EmailField","PasswordField","TextField","NameField","MarketingEmailOptInCheckbox"],"sources":["../../../src/forms/fields/index.js"],"sourcesContent":["export { default as EmailField } from './email-field';\nexport { default as PasswordField } from './password-field';\nexport { default as TextField } from './text-field';\nexport { default as NameField } from './name-field';\nexport { default as MarketingEmailOptInCheckbox } from './marketing-email-opt-out-field';\n"],"mappings":"AAAA,SAASA,OAAO,IAAIC,UAAU,QAAQ,eAAe;AACrD,SAASD,OAAO,IAAIE,aAAa,QAAQ,kBAAkB;AAC3D,SAASF,OAAO,IAAIG,SAAS,QAAQ,cAAc;AACnD,SAASH,OAAO,IAAII,SAAS,QAAQ,cAAc;AACnD,SAASJ,OAAO,IAAIK,2BAA2B,QAAQ,iCAAiC","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/fields/index.scss b/dist/forms/fields/index.scss new file mode 100644 index 00000000..9d9f6dd2 --- /dev/null +++ b/dist/forms/fields/index.scss @@ -0,0 +1,4 @@ +@import "email-field"; +@import "password-field"; +@import "text-field"; +@import "auto-suggested-field"; diff --git a/dist/forms/fields/marketing-email-opt-out-field/index.js b/dist/forms/fields/marketing-email-opt-out-field/index.js new file mode 100644 index 00000000..375a9509 --- /dev/null +++ b/dist/forms/fields/marketing-email-opt-out-field/index.js @@ -0,0 +1,39 @@ +import React from 'react'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Form } from '@openedx/paragon'; +import PropTypes from 'prop-types'; +import messages from './messages'; + +/** + * Marketing email opt in field component. It accepts following handler(s) + * - handleChange for setting value change and + * + * It is responsible for + * - setting value on change (true/false) + */ +const MarketingEmailOptInCheckbox = props => { + const { + formatMessage + } = useIntl(); + const { + name, + value, + handleChange + } = props; + return /*#__PURE__*/React.createElement(Form.Group, { + controlId: "marketingEmailsOptIn", + className: "mb-4" + }, /*#__PURE__*/React.createElement(Form.Checkbox, { + name: name, + className: "text-gray-800", + checked: !!value, + onChange: handleChange + }, formatMessage(messages.registrationFormMarketingOptInLabel))); +}; +MarketingEmailOptInCheckbox.propTypes = { + name: PropTypes.string.isRequired, + value: PropTypes.bool.isRequired, + handleChange: PropTypes.func.isRequired +}; +export default MarketingEmailOptInCheckbox; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/forms/fields/marketing-email-opt-out-field/index.js.map b/dist/forms/fields/marketing-email-opt-out-field/index.js.map new file mode 100644 index 00000000..6cfbd4d5 --- /dev/null +++ b/dist/forms/fields/marketing-email-opt-out-field/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["React","useIntl","Form","PropTypes","messages","MarketingEmailOptInCheckbox","props","formatMessage","name","value","handleChange","createElement","Group","controlId","className","Checkbox","checked","onChange","registrationFormMarketingOptInLabel","propTypes","string","isRequired","bool","func"],"sources":["../../../../src/forms/fields/marketing-email-opt-out-field/index.jsx"],"sourcesContent":["import React from 'react';\n\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport { Form } from '@openedx/paragon';\nimport PropTypes from 'prop-types';\n\nimport messages from './messages';\n\n/**\n * Marketing email opt in field component. It accepts following handler(s)\n * - handleChange for setting value change and\n *\n * It is responsible for\n * - setting value on change (true/false)\n */\nconst MarketingEmailOptInCheckbox = (props) => {\n const { formatMessage } = useIntl();\n const { name, value, handleChange } = props;\n\n return (\n \n \n {formatMessage(messages.registrationFormMarketingOptInLabel)}\n \n \n );\n};\n\nMarketingEmailOptInCheckbox.propTypes = {\n name: PropTypes.string.isRequired,\n value: PropTypes.bool.isRequired,\n handleChange: PropTypes.func.isRequired,\n};\n\nexport default MarketingEmailOptInCheckbox;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AAEzB,SAASC,OAAO,QAAQ,6BAA6B;AACrD,SAASC,IAAI,QAAQ,kBAAkB;AACvC,OAAOC,SAAS,MAAM,YAAY;AAElC,OAAOC,QAAQ,MAAM,YAAY;;AAEjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,2BAA2B,GAAIC,KAAK,IAAK;EAC7C,MAAM;IAAEC;EAAc,CAAC,GAAGN,OAAO,CAAC,CAAC;EACnC,MAAM;IAAEO,IAAI;IAAEC,KAAK;IAAEC;EAAa,CAAC,GAAGJ,KAAK;EAE3C,oBACEN,KAAA,CAAAW,aAAA,CAACT,IAAI,CAACU,KAAK;IAACC,SAAS,EAAC,sBAAsB;IAACC,SAAS,EAAC;EAAM,gBAC3Dd,KAAA,CAAAW,aAAA,CAACT,IAAI,CAACa,QAAQ;IACZP,IAAI,EAAEA,IAAK;IACXM,SAAS,EAAC,eAAe;IACzBE,OAAO,EAAE,CAAC,CAACP,KAAM;IACjBQ,QAAQ,EAAEP;EAAa,GAEtBH,aAAa,CAACH,QAAQ,CAACc,mCAAmC,CAC9C,CACL,CAAC;AAEjB,CAAC;AAEDb,2BAA2B,CAACc,SAAS,GAAG;EACtCX,IAAI,EAAEL,SAAS,CAACiB,MAAM,CAACC,UAAU;EACjCZ,KAAK,EAAEN,SAAS,CAACmB,IAAI,CAACD,UAAU;EAChCX,YAAY,EAAEP,SAAS,CAACoB,IAAI,CAACF;AAC/B,CAAC;AAED,eAAehB,2BAA2B","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/fields/marketing-email-opt-out-field/messages.js b/dist/forms/fields/marketing-email-opt-out-field/messages.js new file mode 100644 index 00000000..505f84f1 --- /dev/null +++ b/dist/forms/fields/marketing-email-opt-out-field/messages.js @@ -0,0 +1,10 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; +const messages = defineMessages({ + registrationFormMarketingOptInLabel: { + id: 'registration.form.marketing.opt.in.label', + defaultMessage: 'I agree that edX may send me marketing messages', + description: 'Label for option to opt in for marketing emails on registration form' + } +}); +export default messages; +//# sourceMappingURL=messages.js.map \ No newline at end of file diff --git a/dist/forms/fields/marketing-email-opt-out-field/messages.js.map b/dist/forms/fields/marketing-email-opt-out-field/messages.js.map new file mode 100644 index 00000000..d7cd1e96 --- /dev/null +++ b/dist/forms/fields/marketing-email-opt-out-field/messages.js.map @@ -0,0 +1 @@ +{"version":3,"file":"messages.js","names":["defineMessages","messages","registrationFormMarketingOptInLabel","id","defaultMessage","description"],"sources":["../../../../src/forms/fields/marketing-email-opt-out-field/messages.jsx"],"sourcesContent":["import { defineMessages } from '@edx/frontend-platform/i18n';\n\nconst messages = defineMessages({\n registrationFormMarketingOptInLabel: {\n id: 'registration.form.marketing.opt.in.label',\n defaultMessage: 'I agree that edX may send me marketing messages',\n description: 'Label for option to opt in for marketing emails on registration form',\n },\n});\n\nexport default messages;\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,6BAA6B;AAE5D,MAAMC,QAAQ,GAAGD,cAAc,CAAC;EAC9BE,mCAAmC,EAAE;IACnCC,EAAE,EAAE,0CAA0C;IAC9CC,cAAc,EAAE,iDAAiD;IACjEC,WAAW,EAAE;EACf;AACF,CAAC,CAAC;AAEF,eAAeJ,QAAQ","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/fields/name-field/index.js b/dist/forms/fields/name-field/index.js new file mode 100644 index 00000000..31ad10cc --- /dev/null +++ b/dist/forms/fields/name-field/index.js @@ -0,0 +1,55 @@ +function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } +import React from 'react'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import PropTypes from 'prop-types'; +import validateName from './validator'; +import { useDispatch } from '../../../data/storeHooks'; +import { clearRegistrationBackendError } from '../../registration-popup/data/reducers'; +import TextField from '../text-field'; + +/** + * Name field wrapper. It accepts following handlers + * - handleChange for setting value change and + * - handleErrorChange for setting error + * + * It is responsible for + * - Performing name field validations + * - Clearing error on focus + * - Setting value on change + */ +const NameField = props => { + const { + formatMessage + } = useIntl(); + const dispatch = useDispatch(); + const { + handleErrorChange, + errorMessage = '' + } = props; + const handleOnBlur = e => { + const { + value + } = e.target; + const fieldError = validateName(value, formatMessage); + if (fieldError) { + handleErrorChange('name', fieldError); + } + }; + const handleOnFocus = () => { + handleErrorChange('name', ''); + dispatch(clearRegistrationBackendError('name')); + }; + return /*#__PURE__*/React.createElement(TextField, _extends({}, props, { + errorMessage: errorMessage, + handleBlur: handleOnBlur, + handleFocus: handleOnFocus + })); +}; +NameField.propTypes = { + errorMessage: PropTypes.string, + value: PropTypes.string.isRequired, + handleChange: PropTypes.func.isRequired, + handleErrorChange: PropTypes.func.isRequired +}; +export default NameField; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/forms/fields/name-field/index.js.map b/dist/forms/fields/name-field/index.js.map new file mode 100644 index 00000000..2f875f3e --- /dev/null +++ b/dist/forms/fields/name-field/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["React","useIntl","PropTypes","validateName","useDispatch","clearRegistrationBackendError","TextField","NameField","props","formatMessage","dispatch","handleErrorChange","errorMessage","handleOnBlur","e","value","target","fieldError","handleOnFocus","createElement","_extends","handleBlur","handleFocus","propTypes","string","isRequired","handleChange","func"],"sources":["../../../../src/forms/fields/name-field/index.jsx"],"sourcesContent":["import React from 'react';\n\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport PropTypes from 'prop-types';\n\nimport validateName from './validator';\nimport { useDispatch } from '../../../data/storeHooks';\nimport { clearRegistrationBackendError } from '../../registration-popup/data/reducers';\nimport TextField from '../text-field';\n\n/**\n * Name field wrapper. It accepts following handlers\n * - handleChange for setting value change and\n * - handleErrorChange for setting error\n *\n * It is responsible for\n * - Performing name field validations\n * - Clearing error on focus\n * - Setting value on change\n */\nconst NameField = (props) => {\n const { formatMessage } = useIntl();\n const dispatch = useDispatch();\n\n const {\n handleErrorChange,\n errorMessage = '',\n } = props;\n\n const handleOnBlur = (e) => {\n const { value } = e.target;\n\n const fieldError = validateName(value, formatMessage);\n if (fieldError) {\n handleErrorChange('name', fieldError);\n }\n };\n\n const handleOnFocus = () => {\n handleErrorChange('name', '');\n dispatch(clearRegistrationBackendError('name'));\n };\n\n return (\n \n );\n};\n\nNameField.propTypes = {\n errorMessage: PropTypes.string,\n value: PropTypes.string.isRequired,\n handleChange: PropTypes.func.isRequired,\n handleErrorChange: PropTypes.func.isRequired,\n};\n\nexport default NameField;\n"],"mappings":";AAAA,OAAOA,KAAK,MAAM,OAAO;AAEzB,SAASC,OAAO,QAAQ,6BAA6B;AACrD,OAAOC,SAAS,MAAM,YAAY;AAElC,OAAOC,YAAY,MAAM,aAAa;AACtC,SAASC,WAAW,QAAQ,0BAA0B;AACtD,SAASC,6BAA6B,QAAQ,wCAAwC;AACtF,OAAOC,SAAS,MAAM,eAAe;;AAErC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,SAAS,GAAIC,KAAK,IAAK;EAC3B,MAAM;IAAEC;EAAc,CAAC,GAAGR,OAAO,CAAC,CAAC;EACnC,MAAMS,QAAQ,GAAGN,WAAW,CAAC,CAAC;EAE9B,MAAM;IACJO,iBAAiB;IACjBC,YAAY,GAAG;EACjB,CAAC,GAAGJ,KAAK;EAET,MAAMK,YAAY,GAAIC,CAAC,IAAK;IAC1B,MAAM;MAAEC;IAAM,CAAC,GAAGD,CAAC,CAACE,MAAM;IAE1B,MAAMC,UAAU,GAAGd,YAAY,CAACY,KAAK,EAAEN,aAAa,CAAC;IACrD,IAAIQ,UAAU,EAAE;MACdN,iBAAiB,CAAC,MAAM,EAAEM,UAAU,CAAC;IACvC;EACF,CAAC;EAED,MAAMC,aAAa,GAAGA,CAAA,KAAM;IAC1BP,iBAAiB,CAAC,MAAM,EAAE,EAAE,CAAC;IAC7BD,QAAQ,CAACL,6BAA6B,CAAC,MAAM,CAAC,CAAC;EACjD,CAAC;EAED,oBACEL,KAAA,CAAAmB,aAAA,CAACb,SAAS,EAAAc,QAAA,KACJZ,KAAK;IACTI,YAAY,EAAEA,YAAa;IAC3BS,UAAU,EAAER,YAAa;IACzBS,WAAW,EAAEJ;EAAc,EAC5B,CAAC;AAEN,CAAC;AAEDX,SAAS,CAACgB,SAAS,GAAG;EACpBX,YAAY,EAAEV,SAAS,CAACsB,MAAM;EAC9BT,KAAK,EAAEb,SAAS,CAACsB,MAAM,CAACC,UAAU;EAClCC,YAAY,EAAExB,SAAS,CAACyB,IAAI,CAACF,UAAU;EACvCd,iBAAiB,EAAET,SAAS,CAACyB,IAAI,CAACF;AACpC,CAAC;AAED,eAAelB,SAAS","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/fields/name-field/messages.js b/dist/forms/fields/name-field/messages.js new file mode 100644 index 00000000..679ceeb2 --- /dev/null +++ b/dist/forms/fields/name-field/messages.js @@ -0,0 +1,15 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; +const messages = defineMessages({ + emptyNameFieldError: { + id: 'empty.name.field.error', + defaultMessage: 'Full name is required', + description: 'Error message for empty fullname field' + }, + nameValidationMessage: { + id: 'name.validation.message', + defaultMessage: 'Enter a valid name', + description: 'Validation message that appears when fullname contain URL' + } +}); +export default messages; +//# sourceMappingURL=messages.js.map \ No newline at end of file diff --git a/dist/forms/fields/name-field/messages.js.map b/dist/forms/fields/name-field/messages.js.map new file mode 100644 index 00000000..259ff038 --- /dev/null +++ b/dist/forms/fields/name-field/messages.js.map @@ -0,0 +1 @@ +{"version":3,"file":"messages.js","names":["defineMessages","messages","emptyNameFieldError","id","defaultMessage","description","nameValidationMessage"],"sources":["../../../../src/forms/fields/name-field/messages.jsx"],"sourcesContent":["import { defineMessages } from '@edx/frontend-platform/i18n';\n\nconst messages = defineMessages({\n emptyNameFieldError: {\n id: 'empty.name.field.error',\n defaultMessage: 'Full name is required',\n description: 'Error message for empty fullname field',\n },\n nameValidationMessage: {\n id: 'name.validation.message',\n defaultMessage: 'Enter a valid name',\n description: 'Validation message that appears when fullname contain URL',\n },\n});\n\nexport default messages;\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,6BAA6B;AAE5D,MAAMC,QAAQ,GAAGD,cAAc,CAAC;EAC9BE,mBAAmB,EAAE;IACnBC,EAAE,EAAE,wBAAwB;IAC5BC,cAAc,EAAE,uBAAuB;IACvCC,WAAW,EAAE;EACf,CAAC;EACDC,qBAAqB,EAAE;IACrBH,EAAE,EAAE,yBAAyB;IAC7BC,cAAc,EAAE,oBAAoB;IACpCC,WAAW,EAAE;EACf;AACF,CAAC,CAAC;AAEF,eAAeJ,QAAQ","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/fields/name-field/validator.js b/dist/forms/fields/name-field/validator.js new file mode 100644 index 00000000..615a2c5d --- /dev/null +++ b/dist/forms/fields/name-field/validator.js @@ -0,0 +1,21 @@ +import messages from './messages'; + +// regex more focused towards url matching +export const URL_REGEX = /[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)?/gi; // eslint-disable-line no-useless-escape + +// regex for html tags +export const HTML_REGEX = /<|>/u; + +// regex from backend +export const INVALID_NAME_REGEX = /https?:\/\/(?:[-\w.]|(?:%[\da-fA-F]{2}))*/g; +const validateName = (value, formatMessage) => { + let fieldError = ''; + if (!value.trim()) { + fieldError = formatMessage(messages.emptyNameFieldError); + } else if (URL_REGEX.test(value) || HTML_REGEX.test(value) || INVALID_NAME_REGEX.test(value)) { + fieldError = formatMessage(messages.nameValidationMessage); + } + return fieldError; +}; +export default validateName; +//# sourceMappingURL=validator.js.map \ No newline at end of file diff --git a/dist/forms/fields/name-field/validator.js.map b/dist/forms/fields/name-field/validator.js.map new file mode 100644 index 00000000..a26410f6 --- /dev/null +++ b/dist/forms/fields/name-field/validator.js.map @@ -0,0 +1 @@ +{"version":3,"file":"validator.js","names":["messages","URL_REGEX","HTML_REGEX","INVALID_NAME_REGEX","validateName","value","formatMessage","fieldError","trim","emptyNameFieldError","test","nameValidationMessage"],"sources":["../../../../src/forms/fields/name-field/validator.js"],"sourcesContent":["import messages from './messages';\n\n// regex more focused towards url matching\nexport const URL_REGEX = /[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)?/gi; // eslint-disable-line no-useless-escape\n\n// regex for html tags\nexport const HTML_REGEX = /<|>/u;\n\n// regex from backend\nexport const INVALID_NAME_REGEX = /https?:\\/\\/(?:[-\\w.]|(?:%[\\da-fA-F]{2}))*/g;\n\nconst validateName = (value, formatMessage) => {\n let fieldError = '';\n if (!value.trim()) {\n fieldError = formatMessage(messages.emptyNameFieldError);\n } else if (URL_REGEX.test(value) || HTML_REGEX.test(value) || INVALID_NAME_REGEX.test(value)) {\n fieldError = formatMessage(messages.nameValidationMessage);\n }\n return fieldError;\n};\n\nexport default validateName;\n"],"mappings":"AAAA,OAAOA,QAAQ,MAAM,YAAY;;AAEjC;AACA,OAAO,MAAMC,SAAS,GAAG,uFAAuF,CAAC,CAAC;;AAElH;AACA,OAAO,MAAMC,UAAU,GAAG,MAAM;;AAEhC;AACA,OAAO,MAAMC,kBAAkB,GAAG,4CAA4C;AAE9E,MAAMC,YAAY,GAAGA,CAACC,KAAK,EAAEC,aAAa,KAAK;EAC7C,IAAIC,UAAU,GAAG,EAAE;EACnB,IAAI,CAACF,KAAK,CAACG,IAAI,CAAC,CAAC,EAAE;IACjBD,UAAU,GAAGD,aAAa,CAACN,QAAQ,CAACS,mBAAmB,CAAC;EAC1D,CAAC,MAAM,IAAIR,SAAS,CAACS,IAAI,CAACL,KAAK,CAAC,IAAIH,UAAU,CAACQ,IAAI,CAACL,KAAK,CAAC,IAAIF,kBAAkB,CAACO,IAAI,CAACL,KAAK,CAAC,EAAE;IAC5FE,UAAU,GAAGD,aAAa,CAACN,QAAQ,CAACW,qBAAqB,CAAC;EAC5D;EACA,OAAOJ,UAAU;AACnB,CAAC;AAED,eAAeH,YAAY","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/fields/password-field/index.js b/dist/forms/fields/password-field/index.js new file mode 100644 index 00000000..4f3498e3 --- /dev/null +++ b/dist/forms/fields/password-field/index.js @@ -0,0 +1,196 @@ +import React, { forwardRef, useState } from 'react'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Form, Icon, IconButton, OverlayTrigger, Tooltip, useToggle } from '@openedx/paragon'; +import { Check, Remove, Visibility, VisibilityOff } from '@openedx/paragon/icons'; +import PropTypes from 'prop-types'; +import messages from './messages'; +import validatePasswordField from './validator'; +import { useDispatch, useSelector } from '../../../data/storeHooks'; +import { LETTER_REGEX, NUMBER_REGEX } from '../../registration-popup/data/constants'; +import { clearRegistrationBackendError, fetchRealtimeValidations } from '../../registration-popup/data/reducers'; +import './index.scss'; + +/** + * Password field component. It accepts following handler(s) + * - handleChange for setting value change + * - handleFocus for clearing the error state + * + * It is responsible for + * - setting value on change + * - clearing the error state + */ +const PasswordField = /*#__PURE__*/forwardRef((props, ref) => { + const { + formatMessage + } = useIntl(); + const dispatch = useDispatch(); + const validationApiRateLimited = useSelector(state => state.register?.validationApiRateLimited); + const { + errorMessage = '', + name, + dataTestId, + value, + handleChange, + handleErrorChange = null, + floatingLabel, + handleBlur = () => {}, + showPasswordTooltip = true + } = props; + const [isPasswordHidden, setHiddenTrue, setHiddenFalse] = useToggle(true); + const [showPasswordRequirements, setShowPasswordRequirements] = useState(false); + const [isFieldFocusOut, setFieldFocusOut] = useState(false); + const handleOnBlur = e => { + const { + name: fieldName, + value: fieldValue + } = e.target; + if (isFieldFocusOut) { + setShowPasswordRequirements(false); + setFieldFocusOut(false); + } + if (fieldName === props.name && e.relatedTarget?.name === 'passwordIcon') { + return; // Do not run validations on password icon click + } + let passwordValue = fieldValue; + if (fieldName === 'passwordIcon') { + // To validate actual password value when onBlur is triggered by focusing out the password icon + passwordValue = props.value; + } + if (handleBlur) { + handleBlur({ + target: { + name: props.name, + value: passwordValue + } + }); + } + setShowPasswordRequirements(showPasswordTooltip && false); + if (handleErrorChange) { + // If rendering from register page + const fieldError = validatePasswordField(passwordValue, formatMessage); + if (fieldError) { + handleErrorChange('password', fieldError); + } else if (!validationApiRateLimited) { + dispatch(fetchRealtimeValidations({ + password: passwordValue + })); + } + } + }; + const handleFocus = e => { + if (e.target?.name === 'passwordIcon') { + return; // Do not clear error on password icon focus + } + if (props.handleFocus) { + props.handleFocus(e); + } + if (handleErrorChange) { + handleErrorChange('password', ''); + dispatch(clearRegistrationBackendError('password')); + } + setShowPasswordRequirements(showPasswordTooltip && true); + }; + const handleKeyDown = e => { + if (e.shiftKey && e.key === 'Tab') { + setFieldFocusOut(true); + } + }; + const HideButton = /*#__PURE__*/React.createElement(IconButton, { + name: "passwordIcon", + src: VisibilityOff, + onFocus: handleFocus, + onBlur: handleOnBlur, + iconAs: Icon, + onClick: setHiddenTrue, + size: "sm", + variant: "secondary", + alt: formatMessage(messages.hidePasswordAlt) + }); + const ShowButton = /*#__PURE__*/React.createElement(IconButton, { + name: "passwordIcon", + src: Visibility, + onFocus: handleFocus, + onBlur: handleOnBlur, + iconAs: Icon, + onClick: setHiddenFalse, + size: "sm", + variant: "secondary", + alt: formatMessage(messages.showPasswordAlt) + }); + const placement = 'bottom-start'; + const tooltip = /*#__PURE__*/React.createElement(Tooltip, { + id: `password-requirement-${placement}` + }, /*#__PURE__*/React.createElement("span", { + id: "letter-check", + className: "d-flex align-items-center" + }, LETTER_REGEX.test(props.value) ? /*#__PURE__*/React.createElement(Icon, { + className: "text-success mr-1", + src: Check + }) : /*#__PURE__*/React.createElement(Icon, { + className: "mr-1 text-light-700", + src: Remove + }), formatMessage(messages.oneLetter)), /*#__PURE__*/React.createElement("span", { + id: "number-check", + className: "d-flex align-items-center" + }, NUMBER_REGEX.test(props.value) ? /*#__PURE__*/React.createElement(Icon, { + className: "text-success mr-1", + src: Check + }) : /*#__PURE__*/React.createElement(Icon, { + className: "mr-1 text-light-700", + src: Remove + }), formatMessage(messages.oneNumber)), /*#__PURE__*/React.createElement("span", { + id: "characters-check", + className: "d-flex align-items-center" + }, props.value.length >= 8 ? /*#__PURE__*/React.createElement(Icon, { + className: "text-success mr-1", + src: Check + }) : /*#__PURE__*/React.createElement(Icon, { + className: "mr-1 text-light-700", + src: Remove + }), formatMessage(messages.eightCharacters))); + return /*#__PURE__*/React.createElement(Form.Group, { + key: name, + controlId: "password", + className: "w-100 mb-4" + }, /*#__PURE__*/React.createElement(OverlayTrigger, { + key: "tooltip", + placement: placement, + overlay: tooltip, + show: showPasswordRequirements + }, /*#__PURE__*/React.createElement(Form.Control, { + ref: ref, + as: "input", + "data-testid": dataTestId, + className: "mr-0", + type: isPasswordHidden ? 'password' : 'text', + name: name, + value: value, + onChange: handleChange, + onFocus: handleFocus, + onBlur: handleOnBlur, + onKeyDown: handleKeyDown, + autoComplete: "current-password", + trailingElement: isPasswordHidden ? ShowButton : HideButton, + floatingLabel: floatingLabel + })), errorMessage !== '' && /*#__PURE__*/React.createElement(Form.Control.Feedback, { + key: "error", + className: "form-text-size validation-error-margin", + hasIcon: false, + "feedback-for": name, + type: "invalid" + }, errorMessage)); +}); +PasswordField.propTypes = { + name: PropTypes.string.isRequired, + dataTestId: PropTypes.string, + value: PropTypes.string.isRequired, + handleChange: PropTypes.func.isRequired, + handleBlur: PropTypes.func, + handleErrorChange: PropTypes.func, + handleFocus: PropTypes.func.isRequired, + errorMessage: PropTypes.string, + floatingLabel: PropTypes.string.isRequired, + showPasswordTooltip: PropTypes.bool +}; +export default PasswordField; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/forms/fields/password-field/index.js.map b/dist/forms/fields/password-field/index.js.map new file mode 100644 index 00000000..7880a740 --- /dev/null +++ b/dist/forms/fields/password-field/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["React","forwardRef","useState","useIntl","Form","Icon","IconButton","OverlayTrigger","Tooltip","useToggle","Check","Remove","Visibility","VisibilityOff","PropTypes","messages","validatePasswordField","useDispatch","useSelector","LETTER_REGEX","NUMBER_REGEX","clearRegistrationBackendError","fetchRealtimeValidations","PasswordField","props","ref","formatMessage","dispatch","validationApiRateLimited","state","register","errorMessage","name","dataTestId","value","handleChange","handleErrorChange","floatingLabel","handleBlur","showPasswordTooltip","isPasswordHidden","setHiddenTrue","setHiddenFalse","showPasswordRequirements","setShowPasswordRequirements","isFieldFocusOut","setFieldFocusOut","handleOnBlur","e","fieldName","fieldValue","target","relatedTarget","passwordValue","fieldError","password","handleFocus","handleKeyDown","shiftKey","key","HideButton","createElement","src","onFocus","onBlur","iconAs","onClick","size","variant","alt","hidePasswordAlt","ShowButton","showPasswordAlt","placement","tooltip","id","className","test","oneLetter","oneNumber","length","eightCharacters","Group","controlId","overlay","show","Control","as","type","onChange","onKeyDown","autoComplete","trailingElement","Feedback","hasIcon","propTypes","string","isRequired","func","bool"],"sources":["../../../../src/forms/fields/password-field/index.jsx"],"sourcesContent":["import React, { forwardRef, useState } from 'react';\n\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport {\n Form, Icon, IconButton, OverlayTrigger, Tooltip, useToggle,\n} from '@openedx/paragon';\nimport {\n Check, Remove, Visibility, VisibilityOff,\n} from '@openedx/paragon/icons';\nimport PropTypes from 'prop-types';\n\nimport messages from './messages';\nimport validatePasswordField from './validator';\nimport { useDispatch, useSelector } from '../../../data/storeHooks';\nimport { LETTER_REGEX, NUMBER_REGEX } from '../../registration-popup/data/constants';\nimport { clearRegistrationBackendError, fetchRealtimeValidations } from '../../registration-popup/data/reducers';\nimport './index.scss';\n\n/**\n * Password field component. It accepts following handler(s)\n * - handleChange for setting value change\n * - handleFocus for clearing the error state\n *\n * It is responsible for\n * - setting value on change\n * - clearing the error state\n */\nconst PasswordField = forwardRef((props, ref) => {\n const { formatMessage } = useIntl();\n\n const dispatch = useDispatch();\n\n const validationApiRateLimited = useSelector(state => state.register?.validationApiRateLimited);\n const {\n errorMessage = '',\n name,\n dataTestId,\n value,\n handleChange,\n handleErrorChange = null,\n floatingLabel,\n handleBlur = () => {},\n showPasswordTooltip = true,\n } = props;\n\n const [isPasswordHidden, setHiddenTrue, setHiddenFalse] = useToggle(true);\n const [showPasswordRequirements, setShowPasswordRequirements] = useState(false);\n const [isFieldFocusOut, setFieldFocusOut] = useState(false);\n\n const handleOnBlur = (e) => {\n const { name: fieldName, value: fieldValue } = e.target;\n\n if (isFieldFocusOut) {\n setShowPasswordRequirements(false);\n setFieldFocusOut(false);\n }\n\n if (fieldName === props.name && e.relatedTarget?.name === 'passwordIcon') {\n return; // Do not run validations on password icon click\n }\n\n let passwordValue = fieldValue;\n if (fieldName === 'passwordIcon') {\n // To validate actual password value when onBlur is triggered by focusing out the password icon\n passwordValue = props.value;\n }\n\n if (handleBlur) {\n handleBlur({\n target: {\n name: props.name,\n value: passwordValue,\n },\n });\n }\n\n setShowPasswordRequirements(showPasswordTooltip && false);\n if (handleErrorChange) { // If rendering from register page\n const fieldError = validatePasswordField(passwordValue, formatMessage);\n if (fieldError) {\n handleErrorChange('password', fieldError);\n } else if (!validationApiRateLimited) {\n dispatch(fetchRealtimeValidations({ password: passwordValue }));\n }\n }\n };\n\n const handleFocus = (e) => {\n if (e.target?.name === 'passwordIcon') {\n return; // Do not clear error on password icon focus\n }\n\n if (props.handleFocus) {\n props.handleFocus(e);\n }\n if (handleErrorChange) {\n handleErrorChange('password', '');\n dispatch(clearRegistrationBackendError('password'));\n }\n setShowPasswordRequirements(showPasswordTooltip && true);\n };\n\n const handleKeyDown = (e) => {\n if (e.shiftKey && e.key === 'Tab') {\n setFieldFocusOut(true);\n }\n };\n\n const HideButton = (\n \n );\n\n const ShowButton = (\n \n );\n\n const placement = 'bottom-start';\n const tooltip = (\n \n \n {LETTER_REGEX.test(props.value)\n ? \n : }\n {formatMessage(messages.oneLetter)}\n \n \n {NUMBER_REGEX.test(props.value)\n ? \n : }\n {formatMessage(messages.oneNumber)}\n \n \n {props.value.length >= 8\n ? \n : }\n {formatMessage(messages.eightCharacters)}\n \n \n );\n\n return (\n \n \n \n \n {errorMessage !== '' && (\n \n {errorMessage}\n \n )}\n \n );\n});\n\nPasswordField.propTypes = {\n name: PropTypes.string.isRequired,\n dataTestId: PropTypes.string,\n value: PropTypes.string.isRequired,\n handleChange: PropTypes.func.isRequired,\n handleBlur: PropTypes.func,\n handleErrorChange: PropTypes.func,\n handleFocus: PropTypes.func.isRequired,\n errorMessage: PropTypes.string,\n floatingLabel: PropTypes.string.isRequired,\n showPasswordTooltip: PropTypes.bool,\n};\n\nexport default PasswordField;\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/fields/password-field/index.scss b/dist/forms/fields/password-field/index.scss new file mode 100644 index 00000000..21d2200e --- /dev/null +++ b/dist/forms/fields/password-field/index.scss @@ -0,0 +1,8 @@ +.pgn__form-text-valid > div { + color: #333333 !important; +} + +.validation-error-margin { + margin-top: 10px !important; + margin-bottom: 10px !important; +} diff --git a/dist/forms/fields/password-field/messages.js b/dist/forms/fields/password-field/messages.js new file mode 100644 index 00000000..4d2be74f --- /dev/null +++ b/dist/forms/fields/password-field/messages.js @@ -0,0 +1,35 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; +const messages = defineMessages({ + showPasswordAlt: { + id: 'show.password', + defaultMessage: 'Show password', + description: 'aria label for show password icon on password field' + }, + hidePasswordAlt: { + id: 'hide.password', + defaultMessage: 'Hide password', + description: 'aria label for hide password icon on password field' + }, + oneLetter: { + id: 'one.letter', + defaultMessage: '1 letter', + description: 'password requirement to have 1 letter' + }, + oneNumber: { + id: 'one.number', + defaultMessage: '1 number', + description: 'password requirement to have 1 number' + }, + eightCharacters: { + id: 'eight.characters', + defaultMessage: '8 characters', + description: 'password requirement to have a minimum of 8 characters' + }, + passwordValidationMessage: { + id: 'password.validation.message', + defaultMessage: 'Password criteria has not been met', + description: 'Error message for empty or invalid password' + } +}); +export default messages; +//# sourceMappingURL=messages.js.map \ No newline at end of file diff --git a/dist/forms/fields/password-field/messages.js.map b/dist/forms/fields/password-field/messages.js.map new file mode 100644 index 00000000..1374b2bd --- /dev/null +++ b/dist/forms/fields/password-field/messages.js.map @@ -0,0 +1 @@ +{"version":3,"file":"messages.js","names":["defineMessages","messages","showPasswordAlt","id","defaultMessage","description","hidePasswordAlt","oneLetter","oneNumber","eightCharacters","passwordValidationMessage"],"sources":["../../../../src/forms/fields/password-field/messages.jsx"],"sourcesContent":["import { defineMessages } from '@edx/frontend-platform/i18n';\n\nconst messages = defineMessages({\n showPasswordAlt: {\n id: 'show.password',\n defaultMessage: 'Show password',\n description: 'aria label for show password icon on password field',\n },\n hidePasswordAlt: {\n id: 'hide.password',\n defaultMessage: 'Hide password',\n description: 'aria label for hide password icon on password field',\n },\n oneLetter: {\n id: 'one.letter',\n defaultMessage: '1 letter',\n description: 'password requirement to have 1 letter',\n },\n oneNumber: {\n id: 'one.number',\n defaultMessage: '1 number',\n description: 'password requirement to have 1 number',\n },\n eightCharacters: {\n id: 'eight.characters',\n defaultMessage: '8 characters',\n description: 'password requirement to have a minimum of 8 characters',\n },\n passwordValidationMessage: {\n id: 'password.validation.message',\n defaultMessage: 'Password criteria has not been met',\n description: 'Error message for empty or invalid password',\n },\n});\n\nexport default messages;\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,6BAA6B;AAE5D,MAAMC,QAAQ,GAAGD,cAAc,CAAC;EAC9BE,eAAe,EAAE;IACfC,EAAE,EAAE,eAAe;IACnBC,cAAc,EAAE,eAAe;IAC/BC,WAAW,EAAE;EACf,CAAC;EACDC,eAAe,EAAE;IACfH,EAAE,EAAE,eAAe;IACnBC,cAAc,EAAE,eAAe;IAC/BC,WAAW,EAAE;EACf,CAAC;EACDE,SAAS,EAAE;IACTJ,EAAE,EAAE,YAAY;IAChBC,cAAc,EAAE,UAAU;IAC1BC,WAAW,EAAE;EACf,CAAC;EACDG,SAAS,EAAE;IACTL,EAAE,EAAE,YAAY;IAChBC,cAAc,EAAE,UAAU;IAC1BC,WAAW,EAAE;EACf,CAAC;EACDI,eAAe,EAAE;IACfN,EAAE,EAAE,kBAAkB;IACtBC,cAAc,EAAE,cAAc;IAC9BC,WAAW,EAAE;EACf,CAAC;EACDK,yBAAyB,EAAE;IACzBP,EAAE,EAAE,6BAA6B;IACjCC,cAAc,EAAE,oCAAoC;IACpDC,WAAW,EAAE;EACf;AACF,CAAC,CAAC;AAEF,eAAeJ,QAAQ","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/fields/password-field/validator.js b/dist/forms/fields/password-field/validator.js new file mode 100644 index 00000000..73fb574b --- /dev/null +++ b/dist/forms/fields/password-field/validator.js @@ -0,0 +1,18 @@ +import messages from './messages'; +import { LETTER_REGEX, NUMBER_REGEX } from '../../registration-popup/data/constants'; + +/** + * It validates the password field value + * @param value + * @param formatMessage + * @returns {string} + */ +const validatePasswordField = (value, formatMessage) => { + let fieldError = ''; + if (!value || !LETTER_REGEX.test(value) || !NUMBER_REGEX.test(value) || value.length < 8) { + fieldError = formatMessage(messages.passwordValidationMessage); + } + return fieldError; +}; +export default validatePasswordField; +//# sourceMappingURL=validator.js.map \ No newline at end of file diff --git a/dist/forms/fields/password-field/validator.js.map b/dist/forms/fields/password-field/validator.js.map new file mode 100644 index 00000000..a60479b7 --- /dev/null +++ b/dist/forms/fields/password-field/validator.js.map @@ -0,0 +1 @@ +{"version":3,"file":"validator.js","names":["messages","LETTER_REGEX","NUMBER_REGEX","validatePasswordField","value","formatMessage","fieldError","test","length","passwordValidationMessage"],"sources":["../../../../src/forms/fields/password-field/validator.js"],"sourcesContent":["import messages from './messages';\nimport { LETTER_REGEX, NUMBER_REGEX } from '../../registration-popup/data/constants';\n\n/**\n * It validates the password field value\n * @param value\n * @param formatMessage\n * @returns {string}\n */\nconst validatePasswordField = (value, formatMessage) => {\n let fieldError = '';\n if (!value || !LETTER_REGEX.test(value) || !NUMBER_REGEX.test(value) || value.length < 8) {\n fieldError = formatMessage(messages.passwordValidationMessage);\n }\n return fieldError;\n};\n\nexport default validatePasswordField;\n"],"mappings":"AAAA,OAAOA,QAAQ,MAAM,YAAY;AACjC,SAASC,YAAY,EAAEC,YAAY,QAAQ,yCAAyC;;AAEpF;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,qBAAqB,GAAGA,CAACC,KAAK,EAAEC,aAAa,KAAK;EACtD,IAAIC,UAAU,GAAG,EAAE;EACnB,IAAI,CAACF,KAAK,IAAI,CAACH,YAAY,CAACM,IAAI,CAACH,KAAK,CAAC,IAAI,CAACF,YAAY,CAACK,IAAI,CAACH,KAAK,CAAC,IAAIA,KAAK,CAACI,MAAM,GAAG,CAAC,EAAE;IACxFF,UAAU,GAAGD,aAAa,CAACL,QAAQ,CAACS,yBAAyB,CAAC;EAChE;EACA,OAAOH,UAAU;AACnB,CAAC;AAED,eAAeH,qBAAqB","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/fields/text-field/index.js b/dist/forms/fields/text-field/index.js new file mode 100644 index 00000000..9c9f75d2 --- /dev/null +++ b/dist/forms/fields/text-field/index.js @@ -0,0 +1,66 @@ +import React, { forwardRef } from 'react'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Form } from '@openedx/paragon'; +import PropTypes from 'prop-types'; +import messages from './messages'; +import './index.scss'; +/** + * Text field component. It accepts following handler(s) + * - handleChange for setting value on change + * - handleFocus for clearing the error state + * + * It is responsible for + * - setting value on change + * - clearing error on focus + */ +const TextField = /*#__PURE__*/forwardRef((props, ref) => { + const { + formatMessage + } = useIntl(); + const { + errorMessage, + label, + name, + value, + handleChange, + handleBlur = null, + handleFocus, + autoComplete = '' + } = props; + return /*#__PURE__*/React.createElement(Form.Group, { + controlId: name, + className: "w-100 mb-4" + }, /*#__PURE__*/React.createElement(Form.Control, { + as: "input", + type: "text", + className: "mr-0", + name: name, + value: value, + onChange: handleChange, + onFocus: handleFocus, + onBlur: handleBlur, + autoComplete: autoComplete, + floatingLabel: formatMessage(messages.fieldLabel, { + label + }), + ref: ref + }), errorMessage !== '' && /*#__PURE__*/React.createElement(Form.Control.Feedback, { + key: "error", + className: "form-text-size validation-error-margin", + hasIcon: false, + "feedback-for": name, + type: "invalid" + }, errorMessage)); +}); +TextField.propTypes = { + errorMessage: PropTypes.string.isRequired, + label: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, + handleChange: PropTypes.func.isRequired, + handleFocus: PropTypes.func.isRequired, + handleBlur: PropTypes.func, + autoComplete: PropTypes.string +}; +export default TextField; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/forms/fields/text-field/index.js.map b/dist/forms/fields/text-field/index.js.map new file mode 100644 index 00000000..6b3e729f --- /dev/null +++ b/dist/forms/fields/text-field/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["React","forwardRef","useIntl","Form","PropTypes","messages","TextField","props","ref","formatMessage","errorMessage","label","name","value","handleChange","handleBlur","handleFocus","autoComplete","createElement","Group","controlId","className","Control","as","type","onChange","onFocus","onBlur","floatingLabel","fieldLabel","Feedback","key","hasIcon","propTypes","string","isRequired","func"],"sources":["../../../../src/forms/fields/text-field/index.jsx"],"sourcesContent":["import React, { forwardRef } from 'react';\n\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport { Form } from '@openedx/paragon';\nimport PropTypes from 'prop-types';\n\nimport messages from './messages';\nimport './index.scss';\n/**\n * Text field component. It accepts following handler(s)\n * - handleChange for setting value on change\n * - handleFocus for clearing the error state\n *\n * It is responsible for\n * - setting value on change\n * - clearing error on focus\n */\nconst TextField = forwardRef((props, ref) => {\n const { formatMessage } = useIntl();\n const {\n errorMessage,\n label,\n name,\n value,\n handleChange,\n handleBlur = null,\n handleFocus,\n autoComplete = '',\n } = props;\n\n return (\n \n \n {errorMessage !== '' && (\n \n {errorMessage}\n \n )}\n \n );\n});\n\nTextField.propTypes = {\n errorMessage: PropTypes.string.isRequired,\n label: PropTypes.string.isRequired,\n name: PropTypes.string.isRequired,\n value: PropTypes.string.isRequired,\n handleChange: PropTypes.func.isRequired,\n handleFocus: PropTypes.func.isRequired,\n handleBlur: PropTypes.func,\n autoComplete: PropTypes.string,\n};\n\nexport default TextField;\n"],"mappings":"AAAA,OAAOA,KAAK,IAAIC,UAAU,QAAQ,OAAO;AAEzC,SAASC,OAAO,QAAQ,6BAA6B;AACrD,SAASC,IAAI,QAAQ,kBAAkB;AACvC,OAAOC,SAAS,MAAM,YAAY;AAElC,OAAOC,QAAQ,MAAM,YAAY;AACjC,OAAO,cAAc;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,SAAS,gBAAGL,UAAU,CAAC,CAACM,KAAK,EAAEC,GAAG,KAAK;EAC3C,MAAM;IAAEC;EAAc,CAAC,GAAGP,OAAO,CAAC,CAAC;EACnC,MAAM;IACJQ,YAAY;IACZC,KAAK;IACLC,IAAI;IACJC,KAAK;IACLC,YAAY;IACZC,UAAU,GAAG,IAAI;IACjBC,WAAW;IACXC,YAAY,GAAG;EACjB,CAAC,GAAGV,KAAK;EAET,oBACEP,KAAA,CAAAkB,aAAA,CAACf,IAAI,CAACgB,KAAK;IAACC,SAAS,EAAER,IAAK;IAACS,SAAS,EAAC;EAAY,gBACjDrB,KAAA,CAAAkB,aAAA,CAACf,IAAI,CAACmB,OAAO;IACXC,EAAE,EAAC,OAAO;IACVC,IAAI,EAAC,MAAM;IACXH,SAAS,EAAC,MAAM;IAChBT,IAAI,EAAEA,IAAK;IACXC,KAAK,EAAEA,KAAM;IACbY,QAAQ,EAAEX,YAAa;IACvBY,OAAO,EAAEV,WAAY;IACrBW,MAAM,EAAEZ,UAAW;IACnBE,YAAY,EAAEA,YAAa;IAC3BW,aAAa,EAAEnB,aAAa,CAACJ,QAAQ,CAACwB,UAAU,EAAE;MAAElB;IAAM,CAAC,CAAE;IAC7DH,GAAG,EAAEA;EAAI,CACV,CAAC,EACDE,YAAY,KAAK,EAAE,iBAClBV,KAAA,CAAAkB,aAAA,CAACf,IAAI,CAACmB,OAAO,CAACQ,QAAQ;IACpBC,GAAG,EAAC,OAAO;IACXV,SAAS,EAAC,wCAAwC;IAClDW,OAAO,EAAE,KAAM;IACf,gBAAcpB,IAAK;IACnBY,IAAI,EAAC;EAAS,GAEbd,YACoB,CAEf,CAAC;AAEjB,CAAC,CAAC;AAEFJ,SAAS,CAAC2B,SAAS,GAAG;EACpBvB,YAAY,EAAEN,SAAS,CAAC8B,MAAM,CAACC,UAAU;EACzCxB,KAAK,EAAEP,SAAS,CAAC8B,MAAM,CAACC,UAAU;EAClCvB,IAAI,EAAER,SAAS,CAAC8B,MAAM,CAACC,UAAU;EACjCtB,KAAK,EAAET,SAAS,CAAC8B,MAAM,CAACC,UAAU;EAClCrB,YAAY,EAAEV,SAAS,CAACgC,IAAI,CAACD,UAAU;EACvCnB,WAAW,EAAEZ,SAAS,CAACgC,IAAI,CAACD,UAAU;EACtCpB,UAAU,EAAEX,SAAS,CAACgC,IAAI;EAC1BnB,YAAY,EAAEb,SAAS,CAAC8B;AAC1B,CAAC;AAED,eAAe5B,SAAS","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/fields/text-field/index.scss b/dist/forms/fields/text-field/index.scss new file mode 100644 index 00000000..31b2af24 --- /dev/null +++ b/dist/forms/fields/text-field/index.scss @@ -0,0 +1,3 @@ +.validation-error-margin { + margin-top: 10px !important; +} diff --git a/dist/forms/fields/text-field/messages.js b/dist/forms/fields/text-field/messages.js new file mode 100644 index 00000000..cc2f8fe2 --- /dev/null +++ b/dist/forms/fields/text-field/messages.js @@ -0,0 +1,10 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; +const messages = defineMessages({ + fieldLabel: { + id: 'registration.form.full.name.label', + defaultMessage: '{label}', + description: 'Label for input field' + } +}); +export default messages; +//# sourceMappingURL=messages.js.map \ No newline at end of file diff --git a/dist/forms/fields/text-field/messages.js.map b/dist/forms/fields/text-field/messages.js.map new file mode 100644 index 00000000..9a6254e6 --- /dev/null +++ b/dist/forms/fields/text-field/messages.js.map @@ -0,0 +1 @@ +{"version":3,"file":"messages.js","names":["defineMessages","messages","fieldLabel","id","defaultMessage","description"],"sources":["../../../../src/forms/fields/text-field/messages.jsx"],"sourcesContent":["import { defineMessages } from '@edx/frontend-platform/i18n';\n\nconst messages = defineMessages({\n fieldLabel: {\n id: 'registration.form.full.name.label',\n defaultMessage: '{label}',\n description: 'Label for input field',\n },\n});\n\nexport default messages;\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,6BAA6B;AAE5D,MAAMC,QAAQ,GAAGD,cAAc,CAAC;EAC9BE,UAAU,EAAE;IACVC,EAAE,EAAE,mCAAmC;IACvCC,cAAc,EAAE,SAAS;IACzBC,WAAW,EAAE;EACf;AACF,CAAC,CAAC;AAEF,eAAeJ,QAAQ","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/index.js b/dist/forms/index.js new file mode 100644 index 00000000..4eb9ae41 --- /dev/null +++ b/dist/forms/index.js @@ -0,0 +1,21 @@ +export { default as RegistrationForm } from './registration-popup'; +export { default as registerReducer } from './registration-popup/data/reducers'; +export { default as registerSaga } from './registration-popup/data/sagas'; +export { storeName as registerStoreName } from './registration-popup/data/reducers'; +export { default as LoginForm } from './login-popup'; +export { default as loginReducer } from './login-popup/data/reducers'; +export { default as loginSaga } from './login-popup/data/sagas'; +export { storeName as loginStoreName } from './login-popup/data/reducers'; +export { default as ForgotPasswordForm } from './reset-password-popup/forgot-password'; +export { default as forgotPasswordReducer } from './reset-password-popup/forgot-password/data/reducers'; +export { default as forgotPasswordSaga } from './reset-password-popup/forgot-password/data/sagas'; +export { storeName as forgotPasswordStoreName } from './reset-password-popup/forgot-password/data/reducers'; +export { default as ResetPasswordForm } from './reset-password-popup/reset-password'; +export { default as resetPasswordReducer } from './reset-password-popup/reset-password/data/reducers'; +export { storeName as resetPasswordStoreName } from './reset-password-popup/reset-password/data/reducers'; +export { default as resetPasswordSaga } from './reset-password-popup/reset-password/data/sagas'; +export { default as ProgressiveProfilingForm } from './progressive-profiling-popup'; +export { default as progressiveProfilingReducer } from './progressive-profiling-popup/data/reducers'; +export { default as progressiveProfilingSaga } from './progressive-profiling-popup/data/sagas'; +export { storeName as progressiveProfilingStoreName } from './progressive-profiling-popup/data/reducers'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/forms/index.js.map b/dist/forms/index.js.map new file mode 100644 index 00000000..78c91d32 --- /dev/null +++ b/dist/forms/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["default","RegistrationForm","registerReducer","registerSaga","storeName","registerStoreName","LoginForm","loginReducer","loginSaga","loginStoreName","ForgotPasswordForm","forgotPasswordReducer","forgotPasswordSaga","forgotPasswordStoreName","ResetPasswordForm","resetPasswordReducer","resetPasswordStoreName","resetPasswordSaga","ProgressiveProfilingForm","progressiveProfilingReducer","progressiveProfilingSaga","progressiveProfilingStoreName"],"sources":["../../src/forms/index.jsx"],"sourcesContent":["export { default as RegistrationForm } from './registration-popup';\nexport { default as registerReducer } from './registration-popup/data/reducers';\nexport { default as registerSaga } from './registration-popup/data/sagas';\nexport { storeName as registerStoreName } from './registration-popup/data/reducers';\n\nexport { default as LoginForm } from './login-popup';\nexport { default as loginReducer } from './login-popup/data/reducers';\nexport { default as loginSaga } from './login-popup/data/sagas';\nexport { storeName as loginStoreName } from './login-popup/data/reducers';\n\nexport { default as ForgotPasswordForm } from './reset-password-popup/forgot-password';\nexport { default as forgotPasswordReducer } from './reset-password-popup/forgot-password/data/reducers';\nexport { default as forgotPasswordSaga } from './reset-password-popup/forgot-password/data/sagas';\nexport { storeName as forgotPasswordStoreName } from './reset-password-popup/forgot-password/data/reducers';\n\nexport { default as ResetPasswordForm } from './reset-password-popup/reset-password';\nexport { default as resetPasswordReducer } from './reset-password-popup/reset-password/data/reducers';\nexport { storeName as resetPasswordStoreName } from './reset-password-popup/reset-password/data/reducers';\nexport { default as resetPasswordSaga } from './reset-password-popup/reset-password/data/sagas';\n\nexport { default as ProgressiveProfilingForm } from './progressive-profiling-popup';\nexport { default as progressiveProfilingReducer } from './progressive-profiling-popup/data/reducers';\nexport { default as progressiveProfilingSaga } from './progressive-profiling-popup/data/sagas';\nexport { storeName as progressiveProfilingStoreName } from './progressive-profiling-popup/data/reducers';\n"],"mappings":"AAAA,SAASA,OAAO,IAAIC,gBAAgB,QAAQ,sBAAsB;AAClE,SAASD,OAAO,IAAIE,eAAe,QAAQ,oCAAoC;AAC/E,SAASF,OAAO,IAAIG,YAAY,QAAQ,iCAAiC;AACzE,SAASC,SAAS,IAAIC,iBAAiB,QAAQ,oCAAoC;AAEnF,SAASL,OAAO,IAAIM,SAAS,QAAQ,eAAe;AACpD,SAASN,OAAO,IAAIO,YAAY,QAAQ,6BAA6B;AACrE,SAASP,OAAO,IAAIQ,SAAS,QAAQ,0BAA0B;AAC/D,SAASJ,SAAS,IAAIK,cAAc,QAAQ,6BAA6B;AAEzE,SAAST,OAAO,IAAIU,kBAAkB,QAAQ,wCAAwC;AACtF,SAASV,OAAO,IAAIW,qBAAqB,QAAQ,sDAAsD;AACvG,SAASX,OAAO,IAAIY,kBAAkB,QAAQ,mDAAmD;AACjG,SAASR,SAAS,IAAIS,uBAAuB,QAAQ,sDAAsD;AAE3G,SAASb,OAAO,IAAIc,iBAAiB,QAAQ,uCAAuC;AACpF,SAASd,OAAO,IAAIe,oBAAoB,QAAQ,qDAAqD;AACrG,SAASX,SAAS,IAAIY,sBAAsB,QAAQ,qDAAqD;AACzG,SAAShB,OAAO,IAAIiB,iBAAiB,QAAQ,kDAAkD;AAE/F,SAASjB,OAAO,IAAIkB,wBAAwB,QAAQ,+BAA+B;AACnF,SAASlB,OAAO,IAAImB,2BAA2B,QAAQ,6CAA6C;AACpG,SAASnB,OAAO,IAAIoB,wBAAwB,QAAQ,0CAA0C;AAC9F,SAAShB,SAAS,IAAIiB,6BAA6B,QAAQ,6CAA6C","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/index.scss b/dist/forms/index.scss new file mode 100644 index 00000000..70b7e929 --- /dev/null +++ b/dist/forms/index.scss @@ -0,0 +1,6 @@ +@import "enterprise-sso-popup"; +@import "fields"; +@import "login-popup"; +@import "progressive-profiling-popup"; +@import "registration-popup"; +@import "reset-password-popup"; diff --git a/dist/forms/login-popup/components/AccountActivationMessage.js b/dist/forms/login-popup/components/AccountActivationMessage.js new file mode 100644 index 00000000..8d90572c --- /dev/null +++ b/dist/forms/login-popup/components/AccountActivationMessage.js @@ -0,0 +1,81 @@ +import React, { useEffect, useRef } from 'react'; +import { getConfig } from '@edx/frontend-platform'; +import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; +import { Alert } from '@openedx/paragon'; +import { CheckCircle, Error } from '@openedx/paragon/icons'; +import PropTypes from 'prop-types'; +import { ACCOUNT_ACTIVATION_MESSAGE } from '../data/constants'; +import messages from '../messages'; + +/** + * Account activation component that holds account activation/confirmation banner logic. + * + * @param {string} messageType - The type of message either its success, info or error. + * + * @returns {JSX.Element} The rendered the account activation banner component. + */ +const AccountActivationMessage = _ref => { + let { + messageType = null + } = _ref; + const { + formatMessage + } = useIntl(); + const alertRef = useRef(null); + const variant = messageType === ACCOUNT_ACTIVATION_MESSAGE.ERROR ? 'danger' : messageType; + const iconMapping = { + [ACCOUNT_ACTIVATION_MESSAGE.SUCCESS]: CheckCircle, + [ACCOUNT_ACTIVATION_MESSAGE.ERROR]: Error + }; + let activationMessage; + let heading; + switch (messageType) { + case ACCOUNT_ACTIVATION_MESSAGE.SUCCESS: + { + heading = formatMessage(messages.accountConfirmationSuccessMessageTitle); + activationMessage = /*#__PURE__*/React.createElement("span", null, formatMessage(messages.accountConfirmationSuccessMessage)); + break; + } + case ACCOUNT_ACTIVATION_MESSAGE.INFO: + { + activationMessage = formatMessage(messages.accountConfirmationInfoMessage); + break; + } + case ACCOUNT_ACTIVATION_MESSAGE.ERROR: + { + const supportLink = /*#__PURE__*/React.createElement(Alert.Link, { + href: `mailto:${getConfig().ACTIVATION_EMAIL_SUPPORT_LINK}` + }, formatMessage(messages.accountConfirmationSupportLink)); + heading = formatMessage(messages.accountConfirmationErrorMessageTitle); + activationMessage = /*#__PURE__*/React.createElement(FormattedMessage, { + id: "account.activation.error.message", + defaultMessage: "Something went wrong, please {supportLink} to resolve this issue.", + description: "Account activation error message", + values: { + supportLink + } + }); + break; + } + default: + break; + } + useEffect(() => { + if (alertRef.current) { + alertRef.current.focus(); + } + }, []); + return activationMessage ? /*#__PURE__*/React.createElement(Alert, { + id: "account-activation-message", + className: "mb-5", + variant: variant, + icon: iconMapping[messageType], + ref: alertRef, + tabIndex: "0" + }, heading && /*#__PURE__*/React.createElement(Alert.Heading, null, heading), activationMessage) : null; +}; +AccountActivationMessage.propTypes = { + messageType: PropTypes.string +}; +export default AccountActivationMessage; +//# sourceMappingURL=AccountActivationMessage.js.map \ No newline at end of file diff --git a/dist/forms/login-popup/components/AccountActivationMessage.js.map b/dist/forms/login-popup/components/AccountActivationMessage.js.map new file mode 100644 index 00000000..a182d88e --- /dev/null +++ b/dist/forms/login-popup/components/AccountActivationMessage.js.map @@ -0,0 +1 @@ +{"version":3,"file":"AccountActivationMessage.js","names":["React","useEffect","useRef","getConfig","FormattedMessage","useIntl","Alert","CheckCircle","Error","PropTypes","ACCOUNT_ACTIVATION_MESSAGE","messages","AccountActivationMessage","_ref","messageType","formatMessage","alertRef","variant","ERROR","iconMapping","SUCCESS","activationMessage","heading","accountConfirmationSuccessMessageTitle","createElement","accountConfirmationSuccessMessage","INFO","accountConfirmationInfoMessage","supportLink","Link","href","ACTIVATION_EMAIL_SUPPORT_LINK","accountConfirmationSupportLink","accountConfirmationErrorMessageTitle","id","defaultMessage","description","values","current","focus","className","icon","ref","tabIndex","Heading","propTypes","string"],"sources":["../../../../src/forms/login-popup/components/AccountActivationMessage.jsx"],"sourcesContent":["import React, { useEffect, useRef } from 'react';\n\nimport { getConfig } from '@edx/frontend-platform';\nimport { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';\nimport { Alert } from '@openedx/paragon';\nimport { CheckCircle, Error } from '@openedx/paragon/icons';\nimport PropTypes from 'prop-types';\n\nimport { ACCOUNT_ACTIVATION_MESSAGE } from '../data/constants';\nimport messages from '../messages';\n\n/**\n * Account activation component that holds account activation/confirmation banner logic.\n *\n * @param {string} messageType - The type of message either its success, info or error.\n *\n * @returns {JSX.Element} The rendered the account activation banner component.\n */\nconst AccountActivationMessage = ({ messageType = null }) => {\n const { formatMessage } = useIntl();\n\n const alertRef = useRef(null);\n const variant = messageType === ACCOUNT_ACTIVATION_MESSAGE.ERROR ? 'danger' : messageType;\n const iconMapping = {\n [ACCOUNT_ACTIVATION_MESSAGE.SUCCESS]: CheckCircle,\n [ACCOUNT_ACTIVATION_MESSAGE.ERROR]: Error,\n };\n\n let activationMessage;\n let heading;\n switch (messageType) {\n case ACCOUNT_ACTIVATION_MESSAGE.SUCCESS: {\n heading = formatMessage(messages.accountConfirmationSuccessMessageTitle);\n activationMessage = {formatMessage(messages.accountConfirmationSuccessMessage)};\n break;\n }\n case ACCOUNT_ACTIVATION_MESSAGE.INFO: {\n activationMessage = formatMessage(messages.accountConfirmationInfoMessage);\n break;\n }\n case ACCOUNT_ACTIVATION_MESSAGE.ERROR: {\n const supportLink = (\n \n {formatMessage(messages.accountConfirmationSupportLink)}\n \n );\n\n heading = formatMessage(messages.accountConfirmationErrorMessageTitle);\n activationMessage = (\n \n );\n break;\n }\n default:\n break;\n }\n\n useEffect(() => {\n if (alertRef.current) {\n alertRef.current.focus();\n }\n }, []);\n\n return activationMessage ? (\n \n {heading && {heading}}\n {activationMessage}\n \n ) : null;\n};\n\nAccountActivationMessage.propTypes = {\n messageType: PropTypes.string,\n};\n\nexport default AccountActivationMessage;\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/login-popup/components/LoginFailureAlert.js b/dist/forms/login-popup/components/LoginFailureAlert.js new file mode 100644 index 00000000..d678b4e4 --- /dev/null +++ b/dist/forms/login-popup/components/LoginFailureAlert.js @@ -0,0 +1,138 @@ +import React from 'react'; +import { getConfig } from '@edx/frontend-platform'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Alert, Hyperlink } from '@openedx/paragon'; +import PropTypes from 'prop-types'; +import { setCurrentOpenedForm } from '../../../authn-component/data/reducers'; +import { FORBIDDEN_REQUEST, FORGOT_PASSWORD_FORM, INTERNAL_SERVER_ERROR, INVALID_FORM, TPA_AUTHENTICATION_FAILURE } from '../../../data/constants'; +import { useDispatch } from '../../../data/storeHooks'; +import { ACCOUNT_LOCKED_OUT, ALLOWED_DOMAIN_LOGIN_ERROR, FAILED_LOGIN_ATTEMPT, INACTIVE_USER, INCORRECT_EMAIL_PASSWORD, NON_COMPLIANT_PASSWORD_EXCEPTION } from '../data/constants'; +import messages from '../messages'; + +/** + * LoginFailureAlert component that is responsible to show error alert based on error code. + * It accepts the following props + * - errorCode + * - context + */ + +const LoginFailureAlert = props => { + const dispatch = useDispatch(); + const { + formatMessage + } = useIntl(); + const { + context = {}, + errorCode + } = props; + const handleResetPasswordLinkClick = event => { + event.preventDefault(); + dispatch(setCurrentOpenedForm(FORGOT_PASSWORD_FORM)); + }; + if (!errorCode || errorCode === TPA_AUTHENTICATION_FAILURE) { + return null; + } + let resetLink = /*#__PURE__*/React.createElement(Hyperlink, { + destination: "reset", + isInline: true + }, formatMessage(messages.loginIncorrectCredentialsErrorResetLinkText)); + let errorMessage; + switch (errorCode) { + case NON_COMPLIANT_PASSWORD_EXCEPTION: + { + errorMessage = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("strong", null, formatMessage(messages.nonCompliantPasswordTitle)), /*#__PURE__*/React.createElement("p", null, formatMessage(messages.nonCompliantPasswordMessage))); + break; + } + case FORBIDDEN_REQUEST: + errorMessage = /*#__PURE__*/React.createElement("span", null, formatMessage(messages.loginRateLimitReachedMessage)); + break; + case INACTIVE_USER: + { + const supportLink = /*#__PURE__*/React.createElement("a", { + href: context.supportLink + }, formatMessage(messages.contactSupportLink, { + platformName: context.platformName + })); + errorMessage = /*#__PURE__*/React.createElement("span", null, formatMessage(messages.loginInactiveUserError, { + lineBreak: /*#__PURE__*/React.createElement("br", null), + email: /*#__PURE__*/React.createElement("strong", { + className: "data-hj-suppress" + }, context.email), + supportLink + })); + break; + } + case ALLOWED_DOMAIN_LOGIN_ERROR: + { + const url = `${getConfig().LMS_BASE_URL}/dashboard/?tpa_hint=${context.tpaHint}`; + const tpaLink = /*#__PURE__*/React.createElement("a", { + href: url + }, formatMessage(messages.tpaAccountLink, { + provider: context.provider + })); + errorMessage = /*#__PURE__*/React.createElement("span", null, formatMessage(messages.allowedDomainLoginError, { + allowedDomain: context.allowedDomain, + tpaLink + })); + break; + } + case INVALID_FORM: + errorMessage = /*#__PURE__*/React.createElement("span", null, formatMessage(messages.loginFormInvalidErrorMessage)); + break; + case FAILED_LOGIN_ATTEMPT: + { + resetLink = /*#__PURE__*/React.createElement(Hyperlink, { + className: "popup_login_form__inline_link-cursor", + onClick: handleResetPasswordLinkClick, + isInline: true + }, formatMessage(messages.loginIncorrectCredentialsErrorBeforeAccountBlockedText)); + errorMessage = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", null, formatMessage(messages.loginIncorrectCredentialsErrorAttemptsText1, { + remainingAttempts: context.remainingAttempts + })), /*#__PURE__*/React.createElement("p", null, formatMessage(messages.loginIncorrectCredentialsErrorAttemptsText2, { + resetLink + }))); + break; + } + case ACCOUNT_LOCKED_OUT: + { + errorMessage = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", null, formatMessage(messages.accountLockedOutMessage1)), /*#__PURE__*/React.createElement("p", null, formatMessage(messages.accountLockedOutMessage2, { + resetLink + }))); + break; + } + case INCORRECT_EMAIL_PASSWORD: + if (context.failureCount <= 1) { + errorMessage = /*#__PURE__*/React.createElement("span", null, formatMessage(messages.loginIncorrectCredentialsError)); + } else if (context.failureCount === 2) { + errorMessage = /*#__PURE__*/React.createElement("span", null, formatMessage(messages.loginIncorrectCredentialsErrorWithResetLink, { + resetLink + })); + } + break; + case INTERNAL_SERVER_ERROR: + default: + errorMessage = /*#__PURE__*/React.createElement("span", null, formatMessage(messages.internalServerErrorMessage)); + break; + } + return /*#__PURE__*/React.createElement(Alert, { + id: "login-failure-alert", + className: "mb-4", + variant: "danger" + }, formatMessage(messages.loginFailureHeaderTitle), " ", errorMessage); +}; +LoginFailureAlert.propTypes = { + context: PropTypes.shape({ + supportLink: PropTypes.string, + platformName: PropTypes.string, + tpaHint: PropTypes.string, + provider: PropTypes.string, + allowedDomain: PropTypes.string, + remainingAttempts: PropTypes.number, + failureCount: PropTypes.number, + errorMessage: PropTypes.string, + email: PropTypes.string + }), + errorCode: PropTypes.string.isRequired +}; +export default LoginFailureAlert; +//# sourceMappingURL=LoginFailureAlert.js.map \ No newline at end of file diff --git a/dist/forms/login-popup/components/LoginFailureAlert.js.map b/dist/forms/login-popup/components/LoginFailureAlert.js.map new file mode 100644 index 00000000..f932829f --- /dev/null +++ b/dist/forms/login-popup/components/LoginFailureAlert.js.map @@ -0,0 +1 @@ +{"version":3,"file":"LoginFailureAlert.js","names":["React","getConfig","useIntl","Alert","Hyperlink","PropTypes","setCurrentOpenedForm","FORBIDDEN_REQUEST","FORGOT_PASSWORD_FORM","INTERNAL_SERVER_ERROR","INVALID_FORM","TPA_AUTHENTICATION_FAILURE","useDispatch","ACCOUNT_LOCKED_OUT","ALLOWED_DOMAIN_LOGIN_ERROR","FAILED_LOGIN_ATTEMPT","INACTIVE_USER","INCORRECT_EMAIL_PASSWORD","NON_COMPLIANT_PASSWORD_EXCEPTION","messages","LoginFailureAlert","props","dispatch","formatMessage","context","errorCode","handleResetPasswordLinkClick","event","preventDefault","resetLink","createElement","destination","isInline","loginIncorrectCredentialsErrorResetLinkText","errorMessage","Fragment","nonCompliantPasswordTitle","nonCompliantPasswordMessage","loginRateLimitReachedMessage","supportLink","href","contactSupportLink","platformName","loginInactiveUserError","lineBreak","email","className","url","LMS_BASE_URL","tpaHint","tpaLink","tpaAccountLink","provider","allowedDomainLoginError","allowedDomain","loginFormInvalidErrorMessage","onClick","loginIncorrectCredentialsErrorBeforeAccountBlockedText","loginIncorrectCredentialsErrorAttemptsText1","remainingAttempts","loginIncorrectCredentialsErrorAttemptsText2","accountLockedOutMessage1","accountLockedOutMessage2","failureCount","loginIncorrectCredentialsError","loginIncorrectCredentialsErrorWithResetLink","internalServerErrorMessage","id","variant","loginFailureHeaderTitle","propTypes","shape","string","number","isRequired"],"sources":["../../../../src/forms/login-popup/components/LoginFailureAlert.jsx"],"sourcesContent":["import React from 'react';\n\nimport { getConfig } from '@edx/frontend-platform';\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport { Alert, Hyperlink } from '@openedx/paragon';\nimport PropTypes from 'prop-types';\n\nimport { setCurrentOpenedForm } from '../../../authn-component/data/reducers';\nimport {\n FORBIDDEN_REQUEST, FORGOT_PASSWORD_FORM,\n INTERNAL_SERVER_ERROR,\n INVALID_FORM,\n TPA_AUTHENTICATION_FAILURE,\n} from '../../../data/constants';\nimport { useDispatch } from '../../../data/storeHooks';\nimport {\n ACCOUNT_LOCKED_OUT,\n ALLOWED_DOMAIN_LOGIN_ERROR,\n FAILED_LOGIN_ATTEMPT,\n INACTIVE_USER,\n INCORRECT_EMAIL_PASSWORD,\n NON_COMPLIANT_PASSWORD_EXCEPTION,\n} from '../data/constants';\nimport messages from '../messages';\n\n/**\n * LoginFailureAlert component that is responsible to show error alert based on error code.\n * It accepts the following props\n * - errorCode\n * - context\n */\n\nconst LoginFailureAlert = (props) => {\n const dispatch = useDispatch();\n const { formatMessage } = useIntl();\n const { context = {}, errorCode } = props;\n\n const handleResetPasswordLinkClick = (event) => {\n event.preventDefault();\n dispatch(setCurrentOpenedForm(FORGOT_PASSWORD_FORM));\n };\n\n if (!errorCode || errorCode === TPA_AUTHENTICATION_FAILURE) {\n return null;\n }\n\n let resetLink = (\n \n {formatMessage(messages.loginIncorrectCredentialsErrorResetLinkText)}\n \n );\n\n let errorMessage;\n switch (errorCode) {\n case NON_COMPLIANT_PASSWORD_EXCEPTION: {\n errorMessage = (\n <>\n {formatMessage(messages.nonCompliantPasswordTitle)}\n

{formatMessage(messages.nonCompliantPasswordMessage)}

\n \n );\n break;\n }\n case FORBIDDEN_REQUEST:\n errorMessage = {formatMessage(messages.loginRateLimitReachedMessage)};\n break;\n case INACTIVE_USER: {\n const supportLink = (\n \n {formatMessage(messages.contactSupportLink, { platformName: context.platformName })}\n \n );\n errorMessage = (\n \n {formatMessage(messages.loginInactiveUserError, {\n lineBreak:
,\n email: {context.email},\n supportLink,\n })}\n
\n );\n break;\n }\n case ALLOWED_DOMAIN_LOGIN_ERROR: {\n const url = `${getConfig().LMS_BASE_URL}/dashboard/?tpa_hint=${context.tpaHint}`;\n const tpaLink = (\n \n {formatMessage(messages.tpaAccountLink, { provider: context.provider })}\n \n );\n errorMessage = (\n \n {formatMessage(messages.allowedDomainLoginError, { allowedDomain: context.allowedDomain, tpaLink })}\n \n );\n break;\n }\n case INVALID_FORM:\n errorMessage = {formatMessage(messages.loginFormInvalidErrorMessage)};\n break;\n case FAILED_LOGIN_ATTEMPT: {\n resetLink = (\n \n {formatMessage(messages.loginIncorrectCredentialsErrorBeforeAccountBlockedText)}\n \n );\n errorMessage = (\n <>\n \n {formatMessage(messages.loginIncorrectCredentialsErrorAttemptsText1, {\n remainingAttempts: context.remainingAttempts,\n })}\n \n

\n {formatMessage(messages.loginIncorrectCredentialsErrorAttemptsText2, { resetLink })}\n

\n \n );\n break;\n }\n case ACCOUNT_LOCKED_OUT: {\n errorMessage = (\n <>\n {formatMessage(messages.accountLockedOutMessage1)}\n

{formatMessage(messages.accountLockedOutMessage2, { resetLink })}

\n \n );\n break;\n }\n case INCORRECT_EMAIL_PASSWORD:\n if (context.failureCount <= 1) {\n errorMessage = {formatMessage(messages.loginIncorrectCredentialsError)};\n } else if (context.failureCount === 2) {\n errorMessage = (\n \n {formatMessage(messages.loginIncorrectCredentialsErrorWithResetLink, { resetLink })}\n \n );\n }\n break;\n case INTERNAL_SERVER_ERROR:\n default:\n errorMessage = {formatMessage(messages.internalServerErrorMessage)};\n break;\n }\n\n return (\n \n {formatMessage(messages.loginFailureHeaderTitle)} { errorMessage }\n \n );\n};\n\nLoginFailureAlert.propTypes = {\n context: PropTypes.shape({\n supportLink: PropTypes.string,\n platformName: PropTypes.string,\n tpaHint: PropTypes.string,\n provider: PropTypes.string,\n allowedDomain: PropTypes.string,\n remainingAttempts: PropTypes.number,\n failureCount: PropTypes.number,\n errorMessage: PropTypes.string,\n email: PropTypes.string,\n }),\n errorCode: PropTypes.string.isRequired,\n};\n\nexport default LoginFailureAlert;\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/login-popup/data/constants.js b/dist/forms/login-popup/data/constants.js new file mode 100644 index 00000000..8d02f6d9 --- /dev/null +++ b/dist/forms/login-popup/data/constants.js @@ -0,0 +1,16 @@ +export const INACTIVE_USER = 'inactive-user'; +export const FAILED_LOGIN_ATTEMPT = 'failed-login-attempt'; +export const ACCOUNT_LOCKED_OUT = 'account-locked-out'; +export const INCORRECT_EMAIL_PASSWORD = 'incorrect-email-or-password'; +export const ALLOWED_DOMAIN_LOGIN_ERROR = 'allowed-domain-login-error'; +export const NON_COMPLIANT_PASSWORD_EXCEPTION = 'NonCompliantPasswordException'; +export const TPA_AUTHENTICATION_FAILURE = 'tpa-authentication-failure'; +export const NUDGE_PASSWORD_CHANGE = 'nudge-password-change'; +export const REQUIRE_PASSWORD_CHANGE = 'require-password-change'; +// Account Activation Message +export const ACCOUNT_ACTIVATION_MESSAGE = { + INFO: 'info', + SUCCESS: 'success', + ERROR: 'error' +}; +//# sourceMappingURL=constants.js.map \ No newline at end of file diff --git a/dist/forms/login-popup/data/constants.js.map b/dist/forms/login-popup/data/constants.js.map new file mode 100644 index 00000000..57fb6f79 --- /dev/null +++ b/dist/forms/login-popup/data/constants.js.map @@ -0,0 +1 @@ +{"version":3,"file":"constants.js","names":["INACTIVE_USER","FAILED_LOGIN_ATTEMPT","ACCOUNT_LOCKED_OUT","INCORRECT_EMAIL_PASSWORD","ALLOWED_DOMAIN_LOGIN_ERROR","NON_COMPLIANT_PASSWORD_EXCEPTION","TPA_AUTHENTICATION_FAILURE","NUDGE_PASSWORD_CHANGE","REQUIRE_PASSWORD_CHANGE","ACCOUNT_ACTIVATION_MESSAGE","INFO","SUCCESS","ERROR"],"sources":["../../../../src/forms/login-popup/data/constants.js"],"sourcesContent":["export const INACTIVE_USER = 'inactive-user';\nexport const FAILED_LOGIN_ATTEMPT = 'failed-login-attempt';\nexport const ACCOUNT_LOCKED_OUT = 'account-locked-out';\nexport const INCORRECT_EMAIL_PASSWORD = 'incorrect-email-or-password';\nexport const ALLOWED_DOMAIN_LOGIN_ERROR = 'allowed-domain-login-error';\nexport const NON_COMPLIANT_PASSWORD_EXCEPTION = 'NonCompliantPasswordException';\nexport const TPA_AUTHENTICATION_FAILURE = 'tpa-authentication-failure';\nexport const NUDGE_PASSWORD_CHANGE = 'nudge-password-change';\nexport const REQUIRE_PASSWORD_CHANGE = 'require-password-change';\n// Account Activation Message\nexport const ACCOUNT_ACTIVATION_MESSAGE = {\n INFO: 'info',\n SUCCESS: 'success',\n ERROR: 'error',\n};\n"],"mappings":"AAAA,OAAO,MAAMA,aAAa,GAAG,eAAe;AAC5C,OAAO,MAAMC,oBAAoB,GAAG,sBAAsB;AAC1D,OAAO,MAAMC,kBAAkB,GAAG,oBAAoB;AACtD,OAAO,MAAMC,wBAAwB,GAAG,6BAA6B;AACrE,OAAO,MAAMC,0BAA0B,GAAG,4BAA4B;AACtE,OAAO,MAAMC,gCAAgC,GAAG,+BAA+B;AAC/E,OAAO,MAAMC,0BAA0B,GAAG,4BAA4B;AACtE,OAAO,MAAMC,qBAAqB,GAAG,uBAAuB;AAC5D,OAAO,MAAMC,uBAAuB,GAAG,yBAAyB;AAChE;AACA,OAAO,MAAMC,0BAA0B,GAAG;EACxCC,IAAI,EAAE,MAAM;EACZC,OAAO,EAAE,SAAS;EAClBC,KAAK,EAAE;AACT,CAAC","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/login-popup/data/hooks.js b/dist/forms/login-popup/data/hooks.js new file mode 100644 index 00000000..ed637553 --- /dev/null +++ b/dist/forms/login-popup/data/hooks.js @@ -0,0 +1,22 @@ +import { useEffect, useState } from 'react'; + +/** + * A react hook used to detect the account activation param in + * url and also remove it once its detected. + * returns account activation param. + */ +const useGetActivationMessage = () => { + const [activationMessage, setActivationMessage] = useState(null); + useEffect(() => { + const url = new URL(window.location.href); + const accountActivationParam = url.searchParams.get('account_activation_status'); + if (accountActivationParam) { + setActivationMessage(accountActivationParam); + url.searchParams.delete('account_activation_status'); + window.history.replaceState(window.history.state, '', url.href); + } + }, []); + return activationMessage; +}; +export default useGetActivationMessage; +//# sourceMappingURL=hooks.js.map \ No newline at end of file diff --git a/dist/forms/login-popup/data/hooks.js.map b/dist/forms/login-popup/data/hooks.js.map new file mode 100644 index 00000000..d045723a --- /dev/null +++ b/dist/forms/login-popup/data/hooks.js.map @@ -0,0 +1 @@ +{"version":3,"file":"hooks.js","names":["useEffect","useState","useGetActivationMessage","activationMessage","setActivationMessage","url","URL","window","location","href","accountActivationParam","searchParams","get","delete","history","replaceState","state"],"sources":["../../../../src/forms/login-popup/data/hooks.js"],"sourcesContent":["import { useEffect, useState } from 'react';\n\n/**\n * A react hook used to detect the account activation param in\n * url and also remove it once its detected.\n * returns account activation param.\n */\nconst useGetActivationMessage = () => {\n const [activationMessage, setActivationMessage] = useState(null);\n\n useEffect(() => {\n const url = new URL(window.location.href);\n\n const accountActivationParam = url.searchParams.get('account_activation_status');\n if (accountActivationParam) {\n setActivationMessage(accountActivationParam);\n url.searchParams.delete('account_activation_status');\n window.history.replaceState(window.history.state, '', url.href);\n }\n }, []);\n\n return activationMessage;\n};\n\nexport default useGetActivationMessage;\n"],"mappings":"AAAA,SAASA,SAAS,EAAEC,QAAQ,QAAQ,OAAO;;AAE3C;AACA;AACA;AACA;AACA;AACA,MAAMC,uBAAuB,GAAGA,CAAA,KAAM;EACpC,MAAM,CAACC,iBAAiB,EAAEC,oBAAoB,CAAC,GAAGH,QAAQ,CAAC,IAAI,CAAC;EAEhED,SAAS,CAAC,MAAM;IACd,MAAMK,GAAG,GAAG,IAAIC,GAAG,CAACC,MAAM,CAACC,QAAQ,CAACC,IAAI,CAAC;IAEzC,MAAMC,sBAAsB,GAAGL,GAAG,CAACM,YAAY,CAACC,GAAG,CAAC,2BAA2B,CAAC;IAChF,IAAIF,sBAAsB,EAAE;MAC1BN,oBAAoB,CAACM,sBAAsB,CAAC;MAC5CL,GAAG,CAACM,YAAY,CAACE,MAAM,CAAC,2BAA2B,CAAC;MACpDN,MAAM,CAACO,OAAO,CAACC,YAAY,CAACR,MAAM,CAACO,OAAO,CAACE,KAAK,EAAE,EAAE,EAAEX,GAAG,CAACI,IAAI,CAAC;IACjE;EACF,CAAC,EAAE,EAAE,CAAC;EAEN,OAAON,iBAAiB;AAC1B,CAAC;AAED,eAAeD,uBAAuB","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/login-popup/data/reducers.js b/dist/forms/login-popup/data/reducers.js new file mode 100644 index 00000000..a4c22c9a --- /dev/null +++ b/dist/forms/login-popup/data/reducers.js @@ -0,0 +1,80 @@ +function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } +function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } +function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); } +function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } +/** + * Redux slice for managing login state. + * This slice handles the login process, including the submission state, + * login success, and any login errors. + */ + +import { createSlice } from '@reduxjs/toolkit'; +import { COMPLETE_STATE, DEFAULT_STATE, FAILURE_STATE, PENDING_STATE } from '../../../data/constants'; +export const storeName = 'login'; +export const LOGIN_SLICE_NAME = 'login'; +export const loginInitialState = { + submitState: DEFAULT_STATE, + isLoginSSOIntent: false, + loginError: {}, + loginResult: {}, + showResetPasswordSuccessBanner: false +}; +export const loginSlice = createSlice({ + name: LOGIN_SLICE_NAME, + initialState: loginInitialState, + reducers: { + loginUser: state => { + state.submitState = PENDING_STATE; + state.loginError = {}; + }, + loginUserSuccess: (state, _ref) => { + let { + payload + } = _ref; + state.submitState = COMPLETE_STATE; + state.loginResult = payload; + }, + setShowPasswordResetBanner: state => { + state.showResetPasswordSuccessBanner = true; + }, + loginUserFailed: (state, _ref2) => { + let { + payload + } = _ref2; + const { + context, + errorCode, + email, + value + } = payload; + const errorContext = _objectSpread(_objectSpread({}, context), {}, { + email, + errorMessage: value + }); + state.loginError = { + errorCode, + errorContext + }; + state.loginResult = {}; + state.submitState = FAILURE_STATE; + }, + loginErrorClear: state => { + state.loginError = {}; + state.submitState = DEFAULT_STATE; + }, + setLoginSSOIntent: state => { + state.isLoginSSOIntent = true; + } + } +}); +export const { + loginErrorClear, + loginUser, + loginUserSuccess, + loginUserFailed, + setShowPasswordResetBanner, + setLoginSSOIntent +} = loginSlice.actions; +export default loginSlice.reducer; +//# sourceMappingURL=reducers.js.map \ No newline at end of file diff --git a/dist/forms/login-popup/data/reducers.js.map b/dist/forms/login-popup/data/reducers.js.map new file mode 100644 index 00000000..19d41ed2 --- /dev/null +++ b/dist/forms/login-popup/data/reducers.js.map @@ -0,0 +1 @@ +{"version":3,"file":"reducers.js","names":["createSlice","COMPLETE_STATE","DEFAULT_STATE","FAILURE_STATE","PENDING_STATE","storeName","LOGIN_SLICE_NAME","loginInitialState","submitState","isLoginSSOIntent","loginError","loginResult","showResetPasswordSuccessBanner","loginSlice","name","initialState","reducers","loginUser","state","loginUserSuccess","_ref","payload","setShowPasswordResetBanner","loginUserFailed","_ref2","context","errorCode","email","value","errorContext","_objectSpread","errorMessage","loginErrorClear","setLoginSSOIntent","actions","reducer"],"sources":["../../../../src/forms/login-popup/data/reducers.js"],"sourcesContent":["/**\n * Redux slice for managing login state.\n * This slice handles the login process, including the submission state,\n * login success, and any login errors.\n */\n\nimport { createSlice } from '@reduxjs/toolkit';\n\nimport {\n COMPLETE_STATE,\n DEFAULT_STATE,\n FAILURE_STATE,\n PENDING_STATE,\n} from '../../../data/constants';\n\nexport const storeName = 'login';\nexport const LOGIN_SLICE_NAME = 'login';\n\nexport const loginInitialState = {\n submitState: DEFAULT_STATE,\n isLoginSSOIntent: false,\n loginError: {},\n loginResult: {},\n showResetPasswordSuccessBanner: false,\n};\n\nexport const loginSlice = createSlice({\n name: LOGIN_SLICE_NAME,\n initialState: loginInitialState,\n reducers: {\n loginUser: (state) => {\n state.submitState = PENDING_STATE;\n state.loginError = {};\n },\n loginUserSuccess: (state, { payload }) => {\n state.submitState = COMPLETE_STATE;\n state.loginResult = payload;\n },\n setShowPasswordResetBanner: (state) => {\n state.showResetPasswordSuccessBanner = true;\n },\n loginUserFailed: (state, { payload }) => {\n const {\n context,\n errorCode,\n email,\n value,\n } = payload;\n\n const errorContext = { ...context, email, errorMessage: value };\n state.loginError = { errorCode, errorContext };\n state.loginResult = {};\n state.submitState = FAILURE_STATE;\n },\n loginErrorClear: (state) => {\n state.loginError = {};\n state.submitState = DEFAULT_STATE;\n },\n setLoginSSOIntent: (state) => {\n state.isLoginSSOIntent = true;\n },\n },\n});\n\nexport const {\n loginErrorClear,\n loginUser,\n loginUserSuccess,\n loginUserFailed,\n setShowPasswordResetBanner,\n setLoginSSOIntent,\n} = loginSlice.actions;\n\nexport default loginSlice.reducer;\n"],"mappings":";;;;;AAAA;AACA;AACA;AACA;AACA;;AAEA,SAASA,WAAW,QAAQ,kBAAkB;AAE9C,SACEC,cAAc,EACdC,aAAa,EACbC,aAAa,EACbC,aAAa,QACR,yBAAyB;AAEhC,OAAO,MAAMC,SAAS,GAAG,OAAO;AAChC,OAAO,MAAMC,gBAAgB,GAAG,OAAO;AAEvC,OAAO,MAAMC,iBAAiB,GAAG;EAC/BC,WAAW,EAAEN,aAAa;EAC1BO,gBAAgB,EAAE,KAAK;EACvBC,UAAU,EAAE,CAAC,CAAC;EACdC,WAAW,EAAE,CAAC,CAAC;EACfC,8BAA8B,EAAE;AAClC,CAAC;AAED,OAAO,MAAMC,UAAU,GAAGb,WAAW,CAAC;EACpCc,IAAI,EAAER,gBAAgB;EACtBS,YAAY,EAAER,iBAAiB;EAC/BS,QAAQ,EAAE;IACRC,SAAS,EAAGC,KAAK,IAAK;MACpBA,KAAK,CAACV,WAAW,GAAGJ,aAAa;MACjCc,KAAK,CAACR,UAAU,GAAG,CAAC,CAAC;IACvB,CAAC;IACDS,gBAAgB,EAAEA,CAACD,KAAK,EAAAE,IAAA,KAAkB;MAAA,IAAhB;QAAEC;MAAQ,CAAC,GAAAD,IAAA;MACnCF,KAAK,CAACV,WAAW,GAAGP,cAAc;MAClCiB,KAAK,CAACP,WAAW,GAAGU,OAAO;IAC7B,CAAC;IACDC,0BAA0B,EAAGJ,KAAK,IAAK;MACrCA,KAAK,CAACN,8BAA8B,GAAG,IAAI;IAC7C,CAAC;IACDW,eAAe,EAAEA,CAACL,KAAK,EAAAM,KAAA,KAAkB;MAAA,IAAhB;QAAEH;MAAQ,CAAC,GAAAG,KAAA;MAClC,MAAM;QACJC,OAAO;QACPC,SAAS;QACTC,KAAK;QACLC;MACF,CAAC,GAAGP,OAAO;MAEX,MAAMQ,YAAY,GAAAC,aAAA,CAAAA,aAAA,KAAQL,OAAO;QAAEE,KAAK;QAAEI,YAAY,EAAEH;MAAK,EAAE;MAC/DV,KAAK,CAACR,UAAU,GAAG;QAAEgB,SAAS;QAAEG;MAAa,CAAC;MAC9CX,KAAK,CAACP,WAAW,GAAG,CAAC,CAAC;MACtBO,KAAK,CAACV,WAAW,GAAGL,aAAa;IACnC,CAAC;IACD6B,eAAe,EAAGd,KAAK,IAAK;MAC1BA,KAAK,CAACR,UAAU,GAAG,CAAC,CAAC;MACrBQ,KAAK,CAACV,WAAW,GAAGN,aAAa;IACnC,CAAC;IACD+B,iBAAiB,EAAGf,KAAK,IAAK;MAC5BA,KAAK,CAACT,gBAAgB,GAAG,IAAI;IAC/B;EACF;AACF,CAAC,CAAC;AAEF,OAAO,MAAM;EACXuB,eAAe;EACff,SAAS;EACTE,gBAAgB;EAChBI,eAAe;EACfD,0BAA0B;EAC1BW;AACF,CAAC,GAAGpB,UAAU,CAACqB,OAAO;AAEtB,eAAerB,UAAU,CAACsB,OAAO","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/login-popup/data/sagas.js b/dist/forms/login-popup/data/sagas.js new file mode 100644 index 00000000..be5be5e7 --- /dev/null +++ b/dist/forms/login-popup/data/sagas.js @@ -0,0 +1,52 @@ +import { camelCaseObject } from '@edx/frontend-platform'; +import { logError, logInfo } from '@edx/frontend-platform/logging'; +import { call, put, takeEvery } from 'redux-saga/effects'; +import { loginUser, loginUserFailed, loginUserSuccess } from './reducers'; +import loginRequest from './service'; +import { FORBIDDEN_REQUEST, INTERNAL_SERVER_ERROR } from '../../../data/constants'; + +/** + * Saga function for handling new user login. + * @param {object} action - The Redux action object containing the payload. + */ +export function* handleUserLogin(action) { + try { + const { + redirectUrl, + success + } = yield call(loginRequest, action.payload); + yield put(loginUserSuccess({ + redirectUrl, + success + })); + } catch (e) { + const statusCodes = [400]; + if (e.response) { + const { + status + } = e.response; + if (statusCodes.includes(status)) { + yield put(loginUserFailed(camelCaseObject(e.response.data))); + logInfo(e); + } else if (status === 403) { + yield put(loginUserFailed({ + errorCode: FORBIDDEN_REQUEST + })); + logInfo(e); + } else { + yield put(loginUserFailed({ + errorCode: INTERNAL_SERVER_ERROR + })); + logError(e); + } + } + } +} + +/** + * Root Saga function that listens for LOGIN actions and calls the handleUserLogin saga. + */ +export default function* saga() { + yield takeEvery(loginUser.type, handleUserLogin); +} +//# sourceMappingURL=sagas.js.map \ No newline at end of file diff --git a/dist/forms/login-popup/data/sagas.js.map b/dist/forms/login-popup/data/sagas.js.map new file mode 100644 index 00000000..370c3fae --- /dev/null +++ b/dist/forms/login-popup/data/sagas.js.map @@ -0,0 +1 @@ +{"version":3,"file":"sagas.js","names":["camelCaseObject","logError","logInfo","call","put","takeEvery","loginUser","loginUserFailed","loginUserSuccess","loginRequest","FORBIDDEN_REQUEST","INTERNAL_SERVER_ERROR","handleUserLogin","action","redirectUrl","success","payload","e","statusCodes","response","status","includes","data","errorCode","saga","type"],"sources":["../../../../src/forms/login-popup/data/sagas.js"],"sourcesContent":["import { camelCaseObject } from '@edx/frontend-platform';\nimport { logError, logInfo } from '@edx/frontend-platform/logging';\nimport { call, put, takeEvery } from 'redux-saga/effects';\n\nimport {\n loginUser, loginUserFailed, loginUserSuccess,\n} from './reducers';\nimport loginRequest from './service';\nimport { FORBIDDEN_REQUEST, INTERNAL_SERVER_ERROR } from '../../../data/constants';\n\n/**\n * Saga function for handling new user login.\n * @param {object} action - The Redux action object containing the payload.\n */\nexport function* handleUserLogin(action) {\n try {\n const { redirectUrl, success } = yield call(loginRequest, action.payload);\n\n yield put(loginUserSuccess({\n redirectUrl,\n success,\n }));\n } catch (e) {\n const statusCodes = [400];\n if (e.response) {\n const { status } = e.response;\n if (statusCodes.includes(status)) {\n yield put(loginUserFailed(camelCaseObject(e.response.data)));\n logInfo(e);\n } else if (status === 403) {\n yield put(loginUserFailed({ errorCode: FORBIDDEN_REQUEST }));\n logInfo(e);\n } else {\n yield put(loginUserFailed({ errorCode: INTERNAL_SERVER_ERROR }));\n logError(e);\n }\n }\n }\n}\n\n/**\n * Root Saga function that listens for LOGIN actions and calls the handleUserLogin saga.\n */\nexport default function* saga() {\n yield takeEvery(loginUser.type, handleUserLogin);\n}\n"],"mappings":"AAAA,SAASA,eAAe,QAAQ,wBAAwB;AACxD,SAASC,QAAQ,EAAEC,OAAO,QAAQ,gCAAgC;AAClE,SAASC,IAAI,EAAEC,GAAG,EAAEC,SAAS,QAAQ,oBAAoB;AAEzD,SACEC,SAAS,EAAEC,eAAe,EAAEC,gBAAgB,QACvC,YAAY;AACnB,OAAOC,YAAY,MAAM,WAAW;AACpC,SAASC,iBAAiB,EAAEC,qBAAqB,QAAQ,yBAAyB;;AAElF;AACA;AACA;AACA;AACA,OAAO,UAAUC,eAAeA,CAACC,MAAM,EAAE;EACvC,IAAI;IACF,MAAM;MAAEC,WAAW;MAAEC;IAAQ,CAAC,GAAG,MAAMZ,IAAI,CAACM,YAAY,EAAEI,MAAM,CAACG,OAAO,CAAC;IAEzE,MAAMZ,GAAG,CAACI,gBAAgB,CAAC;MACzBM,WAAW;MACXC;IACF,CAAC,CAAC,CAAC;EACL,CAAC,CAAC,OAAOE,CAAC,EAAE;IACV,MAAMC,WAAW,GAAG,CAAC,GAAG,CAAC;IACzB,IAAID,CAAC,CAACE,QAAQ,EAAE;MACd,MAAM;QAAEC;MAAO,CAAC,GAAGH,CAAC,CAACE,QAAQ;MAC7B,IAAID,WAAW,CAACG,QAAQ,CAACD,MAAM,CAAC,EAAE;QAChC,MAAMhB,GAAG,CAACG,eAAe,CAACP,eAAe,CAACiB,CAAC,CAACE,QAAQ,CAACG,IAAI,CAAC,CAAC,CAAC;QAC5DpB,OAAO,CAACe,CAAC,CAAC;MACZ,CAAC,MAAM,IAAIG,MAAM,KAAK,GAAG,EAAE;QACzB,MAAMhB,GAAG,CAACG,eAAe,CAAC;UAAEgB,SAAS,EAAEb;QAAkB,CAAC,CAAC,CAAC;QAC5DR,OAAO,CAACe,CAAC,CAAC;MACZ,CAAC,MAAM;QACL,MAAMb,GAAG,CAACG,eAAe,CAAC;UAAEgB,SAAS,EAAEZ;QAAsB,CAAC,CAAC,CAAC;QAChEV,QAAQ,CAACgB,CAAC,CAAC;MACb;IACF;EACF;AACF;;AAEA;AACA;AACA;AACA,eAAe,UAAUO,IAAIA,CAAA,EAAG;EAC9B,MAAMnB,SAAS,CAACC,SAAS,CAACmB,IAAI,EAAEb,eAAe,CAAC;AAClD","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/login-popup/data/service.js b/dist/forms/login-popup/data/service.js new file mode 100644 index 00000000..e11eb40f --- /dev/null +++ b/dist/forms/login-popup/data/service.js @@ -0,0 +1,28 @@ +import { getConfig } from '@edx/frontend-platform'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; +import QueryString from 'query-string'; + +/** + * Function for making a login request to the server. + * This function sends a POST request to the login endpoint with the provided credentials. + * @param {object} creds - The login credentials to be sent to the server. + * @returns {object} An object containing the redirect URL and success status. + */ +export default async function loginRequest(creds) { + const requestConfig = { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + isPublic: true + }; + const { + data + } = await getAuthenticatedHttpClient().post(`${getConfig().LMS_BASE_URL}/api/user/v2/account/login_session/`, QueryString.stringify(creds), requestConfig).catch(e => { + throw e; + }); + return { + redirectUrl: data.redirect_url || `${getConfig().LMS_BASE_URL}/dashboard`, + success: data.success || false + }; +} +//# sourceMappingURL=service.js.map \ No newline at end of file diff --git a/dist/forms/login-popup/data/service.js.map b/dist/forms/login-popup/data/service.js.map new file mode 100644 index 00000000..d17fe85c --- /dev/null +++ b/dist/forms/login-popup/data/service.js.map @@ -0,0 +1 @@ +{"version":3,"file":"service.js","names":["getConfig","getAuthenticatedHttpClient","QueryString","loginRequest","creds","requestConfig","headers","isPublic","data","post","LMS_BASE_URL","stringify","catch","e","redirectUrl","redirect_url","success"],"sources":["../../../../src/forms/login-popup/data/service.js"],"sourcesContent":["import { getConfig } from '@edx/frontend-platform';\nimport { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';\nimport QueryString from 'query-string';\n\n/**\n * Function for making a login request to the server.\n * This function sends a POST request to the login endpoint with the provided credentials.\n * @param {object} creds - The login credentials to be sent to the server.\n * @returns {object} An object containing the redirect URL and success status.\n */\nexport default async function loginRequest(creds) {\n const requestConfig = {\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n isPublic: true,\n };\n\n const { data } = await getAuthenticatedHttpClient()\n .post(\n `${getConfig().LMS_BASE_URL}/api/user/v2/account/login_session/`,\n QueryString.stringify(creds),\n requestConfig,\n )\n .catch((e) => {\n throw (e);\n });\n\n return {\n redirectUrl: data.redirect_url || `${getConfig().LMS_BASE_URL}/dashboard`,\n success: data.success || false,\n };\n}\n"],"mappings":"AAAA,SAASA,SAAS,QAAQ,wBAAwB;AAClD,SAASC,0BAA0B,QAAQ,6BAA6B;AACxE,OAAOC,WAAW,MAAM,cAAc;;AAEtC;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,eAAeC,YAAYA,CAACC,KAAK,EAAE;EAChD,MAAMC,aAAa,GAAG;IACpBC,OAAO,EAAE;MAAE,cAAc,EAAE;IAAoC,CAAC;IAChEC,QAAQ,EAAE;EACZ,CAAC;EAED,MAAM;IAAEC;EAAK,CAAC,GAAG,MAAMP,0BAA0B,CAAC,CAAC,CAChDQ,IAAI,CACF,GAAET,SAAS,CAAC,CAAC,CAACU,YAAa,qCAAoC,EAChER,WAAW,CAACS,SAAS,CAACP,KAAK,CAAC,EAC5BC,aACF,CAAC,CACAO,KAAK,CAAEC,CAAC,IAAK;IACZ,MAAOA,CAAC;EACV,CAAC,CAAC;EAEJ,OAAO;IACLC,WAAW,EAAEN,IAAI,CAACO,YAAY,IAAK,GAAEf,SAAS,CAAC,CAAC,CAACU,YAAa,YAAW;IACzEM,OAAO,EAAER,IAAI,CAACQ,OAAO,IAAI;EAC3B,CAAC;AACH","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/login-popup/index.js b/dist/forms/login-popup/index.js new file mode 100644 index 00000000..f1a78814 --- /dev/null +++ b/dist/forms/login-popup/index.js @@ -0,0 +1,274 @@ +function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } +function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } +function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); } +function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { getConfig, snakeCaseObject } from '@edx/frontend-platform'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Container, Form, StatefulButton } from '@openedx/paragon'; +import AccountActivationMessage from './components/AccountActivationMessage'; +import LoginFailureAlert from './components/LoginFailureAlert'; +import { NUDGE_PASSWORD_CHANGE, REQUIRE_PASSWORD_CHANGE } from './data/constants'; +import useGetActivationMessage from './data/hooks'; +import { loginUser, setLoginSSOIntent } from './data/reducers'; +import messages from './messages'; +import { setCurrentOpenedForm } from '../../authn-component/data/reducers'; +import { InlineLink, SocialAuthProviders } from '../../common-ui'; +import { COMPLETE_STATE, ENTERPRISE_LOGIN_URL, FAILURE_STATE, FORGOT_PASSWORD_FORM, INVALID_FORM, REGISTRATION_FORM, TPA_AUTHENTICATION_FAILURE } from '../../data/constants'; +import { useDispatch, useSelector } from '../../data/storeHooks'; +import getAllPossibleQueryParams, { moveScrollToTop } from '../../data/utils'; +import { trackForgotPasswordLinkClick, trackLoginPageViewed, trackLoginSuccess, trackRegisterFormToggled } from '../../tracking/trackers/login'; +import AuthenticatedRedirection from '../common-components/AuthenticatedRedirection'; +import SSOFailureAlert from '../common-components/SSOFailureAlert'; +import ThirdPartyAuthAlert from '../common-components/ThirdPartyAuthAlert'; +import { TextField as EmailOrUsernameField, PasswordField } from '../fields'; +import ResetPasswordSuccess from '../reset-password-popup/reset-password/components/ResetPasswordSuccess'; +import './index.scss'; + +/** + * Login form component that holds the login form functionality. + * + * @returns {JSX.Element} The rendered login component along with social auth buttons. + */ +const LoginForm = () => { + const { + formatMessage + } = useIntl(); + const dispatch = useDispatch(); + const queryParams = useMemo(() => getAllPossibleQueryParams(), []); + const emailOrUsernameRef = useRef(null); + const socialAuthnButtonRef = useRef(null); + const errorAlertRef = useRef(null); + const loginFormHeadingRef = useRef(null); + const loginResult = useSelector(state => state.login.loginResult); + const loginErrorCode = useSelector(state => state.login.loginError?.errorCode); + const loginErrorContext = useSelector(state => state.login.loginError?.errorContext); + const providers = useSelector(state => state.commonData.thirdPartyAuthContext?.providers); + const thirdPartyAuthApiStatus = useSelector(state => state.commonData.thirdPartyAuthApiStatus); + const submitState = useSelector(state => state.login.submitState); + const currentProvider = useSelector(state => state.commonData.thirdPartyAuthContext.currentProvider); + const thirdPartyAuthErrorMessage = useSelector(state => state.commonData.thirdPartyAuthContext.errorMessage); + const finishAuthUrl = useSelector(state => state.commonData.thirdPartyAuthContext.finishAuthUrl); + const showResetPasswordSuccessBanner = useSelector(state => state.login.showResetPasswordSuccessBanner); + const accountActivation = useGetActivationMessage(); + const [formFields, setFormFields] = useState({ + emailOrUsername: '', + password: '' + }); + const [formErrors, setFormErrors] = useState({ + emailOrUsername: '', + password: '' + }); + const [errorCode, setErrorCode] = useState({ + type: '', + context: {} + }); + useEffect(() => { + trackLoginPageViewed(); + }, []); + useEffect(() => { + if (thirdPartyAuthApiStatus === COMPLETE_STATE && accountActivation === null) { + if (providers.length > 0 && socialAuthnButtonRef.current) { + socialAuthnButtonRef.current.focus(); + } else if (emailOrUsernameRef.current) { + emailOrUsernameRef.current.focus(); + } + } else if (thirdPartyAuthApiStatus === FAILURE_STATE && accountActivation === null) { + emailOrUsernameRef.current.focus(); + } + }, [accountActivation, thirdPartyAuthApiStatus, providers]); + useEffect(() => { + if (moveScrollToTop) { + moveScrollToTop(loginFormHeadingRef, 'end'); + } + }, []); + useEffect(() => { + if (loginResult.success) { + // clear local storage + trackLoginSuccess(); + localStorage.removeItem('ssoPipelineRedirectionDone'); + } + }, [loginResult]); + useEffect(() => { + if (thirdPartyAuthApiStatus === COMPLETE_STATE && currentProvider === null && localStorage.getItem('ssoPipelineRedirectionDone')) { + localStorage.removeItem('ssoPipelineRedirectionDone'); + } + }, [currentProvider, thirdPartyAuthApiStatus]); + useEffect(() => { + if (loginErrorCode) { + setErrorCode({ + type: loginErrorCode, + context: _objectSpread({}, loginErrorContext) + }); + if (loginErrorCode === NUDGE_PASSWORD_CHANGE || loginErrorCode === REQUIRE_PASSWORD_CHANGE) { + dispatch(setCurrentOpenedForm(FORGOT_PASSWORD_FORM)); + } + if (errorAlertRef.current) { + errorAlertRef.current.focus(); + } + } + }, [dispatch, loginErrorCode, loginErrorContext]); + useEffect(() => { + if (thirdPartyAuthErrorMessage) { + setErrorCode(prevState => ({ + type: TPA_AUTHENTICATION_FAILURE, + count: prevState.count + 1, + context: { + errorMessage: thirdPartyAuthErrorMessage + } + })); + } + }, [thirdPartyAuthErrorMessage]); + useEffect(() => { + if (thirdPartyAuthApiStatus === COMPLETE_STATE && currentProvider) { + dispatch(setLoginSSOIntent()); + if (!localStorage.getItem('ssoPipelineRedirectionDone')) { + localStorage.setItem('ssoPipelineRedirectionDone', true); + } + } + }, [dispatch, currentProvider, thirdPartyAuthApiStatus]); + const validateFormFields = payload => { + const { + emailOrUsername, + password + } = payload; + const fieldErrors = _objectSpread({}, formErrors); + if (emailOrUsername === '') { + fieldErrors.emailOrUsername = formatMessage(messages.usernameOrEmailValidationMessage); + } else if (emailOrUsername.length < 2) { + fieldErrors.emailOrUsername = formatMessage(messages.usernameOrEmailLessCharValidationMessage); + } + if (password === '') { + fieldErrors.password = formatMessage(messages.passwordValidationMessage); + } + return _objectSpread({}, fieldErrors); + }; + const handleOnChange = event => { + const { + name, + value + } = event.target; + setFormFields(prevState => _objectSpread(_objectSpread({}, prevState), {}, { + [name]: value + })); + }; + const handleOnFocus = event => { + const { + name + } = event.target; + setFormErrors(prevErrors => _objectSpread(_objectSpread({}, prevErrors), {}, { + [name]: '' + })); + }; + const handleForgotPasswordClick = () => { + dispatch(setCurrentOpenedForm(FORGOT_PASSWORD_FORM)); + trackForgotPasswordLinkClick(); + }; + const handleSubmit = e => { + e.preventDefault(); + const validationErrors = validateFormFields(formFields); + if (validationErrors.emailOrUsername || validationErrors.password) { + setFormErrors(_objectSpread({}, validationErrors)); + setErrorCode({ + type: INVALID_FORM, + context: {} + }); + if (moveScrollToTop) { + moveScrollToTop(errorAlertRef); + } + return; + } + + // add query params to the payload + const payload = _objectSpread(_objectSpread({}, snakeCaseObject(formFields)), queryParams); + dispatch(loginUser(payload)); + }; + return /*#__PURE__*/React.createElement(Container, { + size: "lg", + className: "authn__popup-container" + }, /*#__PURE__*/React.createElement(AuthenticatedRedirection, { + success: loginResult.success, + redirectUrl: loginResult.redirectUrl, + finishAuthUrl: finishAuthUrl + }), /*#__PURE__*/React.createElement("h1", { + className: "display-1 font-italic text-center mb-0", + "data-testid": "sign-in-heading", + ref: loginFormHeadingRef + }, formatMessage(messages.loginFormHeading1)), /*#__PURE__*/React.createElement("hr", { + className: "heading-separator my-3 my-sm-4" + }), accountActivation && /*#__PURE__*/React.createElement(AccountActivationMessage, { + messageType: accountActivation + }), /*#__PURE__*/React.createElement(SSOFailureAlert, { + errorCode: errorCode.type, + context: errorCode.context, + alertTitle: formatMessage(messages.loginFailureHeaderTitle) + }), !currentProvider && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(SocialAuthProviders, { + ref: socialAuthnButtonRef + }), /*#__PURE__*/React.createElement("div", { + className: "text-center my-3 my-sm-4" + }, formatMessage(messages.loginFormHeading2))), /*#__PURE__*/React.createElement("div", { + ref: errorAlertRef, + tabIndex: "-1", + "aria-live": "assertive" + }, /*#__PURE__*/React.createElement(LoginFailureAlert, { + errorCode: errorCode.type, + context: errorCode.context + })), showResetPasswordSuccessBanner && /*#__PURE__*/React.createElement(ResetPasswordSuccess, null), /*#__PURE__*/React.createElement(ThirdPartyAuthAlert, { + currentProvider: currentProvider + }), /*#__PURE__*/React.createElement(Form, { + id: "login-form", + name: "login-form", + className: "my-3 my-sm-4" + }, /*#__PURE__*/React.createElement(EmailOrUsernameField, { + label: "Username or email", + name: "emailOrUsername", + autoComplete: "username", + value: formFields.emailOrUsername, + errorMessage: formErrors.emailOrUsername, + handleChange: handleOnChange, + handleFocus: handleOnFocus, + ref: emailOrUsernameRef + }), /*#__PURE__*/React.createElement(PasswordField, { + name: "password", + value: formFields.password, + errorMessage: formErrors.password, + handleChange: handleOnChange, + handleFocus: handleOnFocus, + floatingLabel: formatMessage(messages.loginFormPasswordFieldLabel), + showPasswordTooltip: false + }), /*#__PURE__*/React.createElement(InlineLink, { + className: "hyper-link mb-4", + onClick: handleForgotPasswordClick, + linkText: formatMessage(messages.loginFormForgotPasswordButton) + }), /*#__PURE__*/React.createElement("div", { + className: "d-flex flex-column m-0" + }, /*#__PURE__*/React.createElement(StatefulButton, { + id: "login-user", + name: "login-user", + type: "submit", + variant: "primary", + className: "align-self-end login__btn-width authn-btn__pill-shaped", + state: submitState, + labels: { + default: formatMessage(messages.loginFormSignInButton), + pending: '' + }, + onClick: handleSubmit, + onMouseDown: e => e.preventDefault() + }))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(InlineLink, { + className: "mb-2", + onClick: () => { + trackRegisterFormToggled(); + dispatch(setCurrentOpenedForm(REGISTRATION_FORM)); + }, + linkHelpText: formatMessage(messages.loginFormRegistrationHelpText), + linkText: formatMessage(messages.loginFormRegistrationLink) + }), /*#__PURE__*/React.createElement(InlineLink, { + destination: getConfig().LMS_BASE_URL + ENTERPRISE_LOGIN_URL, + linkHelpText: formatMessage(messages.loginFormSchoolAndOrganizationHelpText), + linkText: formatMessage(messages.loginFormSchoolAndOrganizationLink) + }))); +}; +export default LoginForm; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/forms/login-popup/index.js.map b/dist/forms/login-popup/index.js.map new file mode 100644 index 00000000..18eb2a56 --- /dev/null +++ b/dist/forms/login-popup/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["React","useEffect","useMemo","useRef","useState","getConfig","snakeCaseObject","useIntl","Container","Form","StatefulButton","AccountActivationMessage","LoginFailureAlert","NUDGE_PASSWORD_CHANGE","REQUIRE_PASSWORD_CHANGE","useGetActivationMessage","loginUser","setLoginSSOIntent","messages","setCurrentOpenedForm","InlineLink","SocialAuthProviders","COMPLETE_STATE","ENTERPRISE_LOGIN_URL","FAILURE_STATE","FORGOT_PASSWORD_FORM","INVALID_FORM","REGISTRATION_FORM","TPA_AUTHENTICATION_FAILURE","useDispatch","useSelector","getAllPossibleQueryParams","moveScrollToTop","trackForgotPasswordLinkClick","trackLoginPageViewed","trackLoginSuccess","trackRegisterFormToggled","AuthenticatedRedirection","SSOFailureAlert","ThirdPartyAuthAlert","TextField","EmailOrUsernameField","PasswordField","ResetPasswordSuccess","LoginForm","formatMessage","dispatch","queryParams","emailOrUsernameRef","socialAuthnButtonRef","errorAlertRef","loginFormHeadingRef","loginResult","state","login","loginErrorCode","loginError","errorCode","loginErrorContext","errorContext","providers","commonData","thirdPartyAuthContext","thirdPartyAuthApiStatus","submitState","currentProvider","thirdPartyAuthErrorMessage","errorMessage","finishAuthUrl","showResetPasswordSuccessBanner","accountActivation","formFields","setFormFields","emailOrUsername","password","formErrors","setFormErrors","setErrorCode","type","context","length","current","focus","success","localStorage","removeItem","getItem","_objectSpread","prevState","count","setItem","validateFormFields","payload","fieldErrors","usernameOrEmailValidationMessage","usernameOrEmailLessCharValidationMessage","passwordValidationMessage","handleOnChange","event","name","value","target","handleOnFocus","prevErrors","handleForgotPasswordClick","handleSubmit","e","preventDefault","validationErrors","createElement","size","className","redirectUrl","ref","loginFormHeading1","messageType","alertTitle","loginFailureHeaderTitle","Fragment","loginFormHeading2","tabIndex","id","label","autoComplete","handleChange","handleFocus","floatingLabel","loginFormPasswordFieldLabel","showPasswordTooltip","onClick","linkText","loginFormForgotPasswordButton","variant","labels","default","loginFormSignInButton","pending","onMouseDown","linkHelpText","loginFormRegistrationHelpText","loginFormRegistrationLink","destination","LMS_BASE_URL","loginFormSchoolAndOrganizationHelpText","loginFormSchoolAndOrganizationLink"],"sources":["../../../src/forms/login-popup/index.jsx"],"sourcesContent":["import React, {\n useEffect, useMemo, useRef, useState,\n} from 'react';\n\nimport { getConfig, snakeCaseObject } from '@edx/frontend-platform';\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport {\n Container, Form, StatefulButton,\n} from '@openedx/paragon';\n\nimport AccountActivationMessage from './components/AccountActivationMessage';\nimport LoginFailureAlert from './components/LoginFailureAlert';\nimport { NUDGE_PASSWORD_CHANGE, REQUIRE_PASSWORD_CHANGE } from './data/constants';\nimport useGetActivationMessage from './data/hooks';\nimport { loginUser, setLoginSSOIntent } from './data/reducers';\nimport messages from './messages';\nimport { setCurrentOpenedForm } from '../../authn-component/data/reducers';\nimport { InlineLink, SocialAuthProviders } from '../../common-ui';\nimport {\n COMPLETE_STATE,\n ENTERPRISE_LOGIN_URL,\n FAILURE_STATE,\n FORGOT_PASSWORD_FORM,\n INVALID_FORM,\n REGISTRATION_FORM,\n TPA_AUTHENTICATION_FAILURE,\n} from '../../data/constants';\nimport { useDispatch, useSelector } from '../../data/storeHooks';\nimport getAllPossibleQueryParams, { moveScrollToTop } from '../../data/utils';\nimport {\n trackForgotPasswordLinkClick, trackLoginPageViewed, trackLoginSuccess, trackRegisterFormToggled,\n} from '../../tracking/trackers/login';\nimport AuthenticatedRedirection from '../common-components/AuthenticatedRedirection';\nimport SSOFailureAlert from '../common-components/SSOFailureAlert';\nimport ThirdPartyAuthAlert from '../common-components/ThirdPartyAuthAlert';\nimport {\n TextField as EmailOrUsernameField,\n PasswordField,\n} from '../fields';\nimport ResetPasswordSuccess from '../reset-password-popup/reset-password/components/ResetPasswordSuccess';\n\nimport './index.scss';\n\n/**\n * Login form component that holds the login form functionality.\n *\n * @returns {JSX.Element} The rendered login component along with social auth buttons.\n */\nconst LoginForm = () => {\n const { formatMessage } = useIntl();\n const dispatch = useDispatch();\n const queryParams = useMemo(() => getAllPossibleQueryParams(), []);\n\n const emailOrUsernameRef = useRef(null);\n const socialAuthnButtonRef = useRef(null);\n const errorAlertRef = useRef(null);\n const loginFormHeadingRef = useRef(null);\n\n const loginResult = useSelector(state => state.login.loginResult);\n const loginErrorCode = useSelector(state => state.login.loginError?.errorCode);\n const loginErrorContext = useSelector(state => state.login.loginError?.errorContext);\n const providers = useSelector(state => state.commonData.thirdPartyAuthContext?.providers);\n const thirdPartyAuthApiStatus = useSelector(state => state.commonData.thirdPartyAuthApiStatus);\n const submitState = useSelector(state => state.login.submitState);\n const currentProvider = useSelector(state => state.commonData.thirdPartyAuthContext.currentProvider);\n const thirdPartyAuthErrorMessage = useSelector(state => state.commonData.thirdPartyAuthContext.errorMessage);\n const finishAuthUrl = useSelector(state => state.commonData.thirdPartyAuthContext.finishAuthUrl);\n const showResetPasswordSuccessBanner = useSelector(state => state.login.showResetPasswordSuccessBanner);\n\n const accountActivation = useGetActivationMessage();\n\n const [formFields, setFormFields] = useState({\n emailOrUsername: '',\n password: '',\n });\n\n const [formErrors, setFormErrors] = useState({\n emailOrUsername: '',\n password: '',\n });\n const [errorCode, setErrorCode] = useState({ type: '', context: {} });\n\n useEffect(() => {\n trackLoginPageViewed();\n }, []);\n\n useEffect(() => {\n if (thirdPartyAuthApiStatus === COMPLETE_STATE && accountActivation === null) {\n if (providers.length > 0 && socialAuthnButtonRef.current) {\n socialAuthnButtonRef.current.focus();\n } else if (emailOrUsernameRef.current) {\n emailOrUsernameRef.current.focus();\n }\n } else if (thirdPartyAuthApiStatus === FAILURE_STATE && accountActivation === null) {\n emailOrUsernameRef.current.focus();\n }\n }, [accountActivation, thirdPartyAuthApiStatus, providers]);\n\n useEffect(() => {\n if (moveScrollToTop) {\n moveScrollToTop(loginFormHeadingRef, 'end');\n }\n }, []);\n\n useEffect(() => {\n if (loginResult.success) {\n // clear local storage\n trackLoginSuccess();\n localStorage.removeItem('ssoPipelineRedirectionDone');\n }\n }, [loginResult]);\n\n useEffect(() => {\n if (thirdPartyAuthApiStatus === COMPLETE_STATE\n && currentProvider === null\n && localStorage.getItem('ssoPipelineRedirectionDone')\n ) {\n localStorage.removeItem('ssoPipelineRedirectionDone');\n }\n }, [currentProvider, thirdPartyAuthApiStatus]);\n\n useEffect(() => {\n if (loginErrorCode) {\n setErrorCode({\n type: loginErrorCode,\n context: { ...loginErrorContext },\n });\n if (loginErrorCode === NUDGE_PASSWORD_CHANGE || loginErrorCode === REQUIRE_PASSWORD_CHANGE) {\n dispatch(setCurrentOpenedForm(FORGOT_PASSWORD_FORM));\n }\n if (errorAlertRef.current) {\n errorAlertRef.current.focus();\n }\n }\n }, [dispatch, loginErrorCode, loginErrorContext]);\n\n useEffect(() => {\n if (thirdPartyAuthErrorMessage) {\n setErrorCode((prevState) => ({\n type: TPA_AUTHENTICATION_FAILURE,\n count: prevState.count + 1,\n context: {\n errorMessage: thirdPartyAuthErrorMessage,\n },\n }));\n }\n }, [thirdPartyAuthErrorMessage]);\n\n useEffect(() => {\n if (thirdPartyAuthApiStatus === COMPLETE_STATE && currentProvider) {\n dispatch(setLoginSSOIntent());\n if (!localStorage.getItem('ssoPipelineRedirectionDone')) {\n localStorage.setItem('ssoPipelineRedirectionDone', true);\n }\n }\n }, [dispatch, currentProvider, thirdPartyAuthApiStatus]);\n\n const validateFormFields = (payload) => {\n const { emailOrUsername, password } = payload;\n const fieldErrors = { ...formErrors };\n\n if (emailOrUsername === '') {\n fieldErrors.emailOrUsername = formatMessage(messages.usernameOrEmailValidationMessage);\n } else if (emailOrUsername.length < 2) {\n fieldErrors.emailOrUsername = formatMessage(messages.usernameOrEmailLessCharValidationMessage);\n }\n if (password === '') {\n fieldErrors.password = formatMessage(messages.passwordValidationMessage);\n }\n\n return { ...fieldErrors };\n };\n\n const handleOnChange = (event) => {\n const { name, value } = event.target;\n setFormFields(prevState => ({ ...prevState, [name]: value }));\n };\n\n const handleOnFocus = (event) => {\n const { name } = event.target;\n setFormErrors(prevErrors => ({ ...prevErrors, [name]: '' }));\n };\n\n const handleForgotPasswordClick = () => {\n dispatch(setCurrentOpenedForm(FORGOT_PASSWORD_FORM));\n trackForgotPasswordLinkClick();\n };\n\n const handleSubmit = (e) => {\n e.preventDefault();\n\n const validationErrors = validateFormFields(formFields);\n\n if (validationErrors.emailOrUsername || validationErrors.password) {\n setFormErrors({ ...validationErrors });\n setErrorCode({ type: INVALID_FORM, context: {} });\n if (moveScrollToTop) {\n moveScrollToTop(errorAlertRef);\n }\n return;\n }\n\n // add query params to the payload\n const payload = {\n ...snakeCaseObject(formFields),\n ...queryParams,\n };\n dispatch(loginUser(payload));\n };\n\n return (\n \n \n \n {formatMessage(messages.loginFormHeading1)}\n \n
\n {accountActivation && }\n \n {!currentProvider && (\n <>\n \n
\n {formatMessage(messages.loginFormHeading2)}\n
\n \n )}\n
\n \n
\n {showResetPasswordSuccessBanner && }\n \n
\n \n \n \n
\n e.preventDefault()}\n />\n
\n \n
\n {\n trackRegisterFormToggled();\n dispatch(setCurrentOpenedForm(REGISTRATION_FORM));\n }}\n linkHelpText={formatMessage(messages.loginFormRegistrationHelpText)}\n linkText={formatMessage(messages.loginFormRegistrationLink)}\n />\n \n
\n
\n );\n};\n\nexport default LoginForm;\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/login-popup/index.scss b/dist/forms/login-popup/index.scss new file mode 100644 index 00000000..9be9fead --- /dev/null +++ b/dist/forms/login-popup/index.scss @@ -0,0 +1,7 @@ +.login__btn-width { + min-width: 5.75rem !important; +} + +.popup_login_form__inline_link-cursor { + cursor: pointer; +} diff --git a/dist/forms/login-popup/messages.js b/dist/forms/login-popup/messages.js new file mode 100644 index 00000000..5e794af8 --- /dev/null +++ b/dist/forms/login-popup/messages.js @@ -0,0 +1,187 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; +const messages = defineMessages({ + loginFormHeading1: { + id: 'login.form.heading.1', + defaultMessage: 'Sign in', + description: 'Login form main heading' + }, + loginFormSignInButton: { + id: 'login.form.signin.button.text', + defaultMessage: 'Sign in', + description: 'Sign in button label that appears on login page' + }, + loginFormForgotPasswordButton: { + id: 'login.form.forgot.password.button.text', + defaultMessage: 'Forgot Password?', + description: 'Button text for forgot password' + }, + loginFormRegistrationHelpText: { + id: 'login.form.sign.up.help.text', + defaultMessage: 'Don’t have an account yet?', + description: 'Sign up link help text' + }, + loginFormRegistrationLink: { + id: 'login.form.sign.up.link.text', + defaultMessage: 'Create account', + description: 'Text that appears on the registration button' + }, + loginFormSchoolAndOrganizationHelpText: { + id: 'login.form.school.and.organization.help.text', + defaultMessage: 'Have an account through school or organization?', + description: 'Label for school and organization login link' + }, + loginFormSchoolAndOrganizationLink: { + id: 'login.form.school.and.organization.link', + defaultMessage: 'Sign in with your credentials', + description: 'Text that appears on school and organization login link' + }, + loginFormEmailFieldLabel: { + id: 'login.form.email.field.label', + defaultMessage: 'Email', + description: 'Email field label' + }, + loginFormPasswordFieldLabel: { + id: 'login.form.password.field.label', + defaultMessage: 'Password', + description: 'Password field label' + }, + loginFormHeading2: { + id: 'login.form.heading.2', + defaultMessage: 'or', + description: 'Heading that appears between social auth and basic login form' + }, + // error messages + loginFailureHeaderTitle: { + id: 'login.failure.header.title', + defaultMessage: 'We couldn\'t sign you in.', + description: 'Login failure header message.' + }, + loginIncorrectCredentialsErrorResetLinkText: { + id: 'login.incorrect.credentials.error.reset.link.text', + defaultMessage: 'reset your password', + description: 'Reset password link text for incorrect email or password credentials' + }, + loginRateLimitReachedMessage: { + id: 'login.rate.limit.reached.message', + defaultMessage: 'Too many failed login attempts. Try again later.', + description: 'Error message that appears when an anonymous user has made too many failed login attempts' + }, + contactSupportLink: { + id: 'contact.support.link', + defaultMessage: 'contact {platformName} support', + description: 'Link text used in inactive user error message to go to learner help center' + }, + loginInactiveUserError: { + id: 'login.inactive.user.error', + defaultMessage: 'In order to sign in, you need to activate your account.{lineBreak}{lineBreak}We just sent an activation link to {email}. If you do not receive an email, check your spam folders or {supportLink}.', + description: 'Activation account message for inactive account' + }, + tpaAccountLink: { + id: 'tpa.account.link', + defaultMessage: '{provider} account', + description: 'Link text error message used to go to SSO when staff user try to login through password.' + }, + allowedDomainLoginError: { + id: 'allowed.domain.login.error', + defaultMessage: 'As {allowedDomain} user, You must login with your {allowedDomain} {tpaLink}.', + description: 'Display this error message when staff user try to login through password' + }, + loginFormInvalidErrorMessage: { + id: 'login.form.invalid.error.message', + defaultMessage: 'Please fill in the fields below.', + description: 'Login form empty input user message' + }, + loginIncorrectCredentialsErrorAttemptsText1: { + id: 'login.incorrect.credentials.error.attempts.text.1', + defaultMessage: 'The username, email or password you entered is incorrect. You have {remainingAttempts} more sign in attempts before your account is temporarily locked.', + description: 'Error message for incorrect email or password' + }, + loginIncorrectCredentialsErrorAttemptsText2: { + id: 'login.incorrect.credentials.error.attempts.text.2', + defaultMessage: "If you've forgotten your password, {resetLink}", + description: 'Part of error message for incorrect email or password' + }, + accountLockedOutMessage1: { + id: 'account.locked.out.message.1', + defaultMessage: 'To protect your account, it\'s been temporarily locked. Try again in 30 minutes.', + description: 'Part of message for when user account has been locked out after multiple failed login attempts' + }, + accountLockedOutMessage2: { + id: 'account.locked.out.message.2', + defaultMessage: 'To be on the safe side, you can {resetLink} before trying again.', + description: 'Part of message for when user account has been locked out after multiple failed login attempts' + }, + loginIncorrectCredentialsError: { + id: 'login.incorrect.credentials.error', + defaultMessage: 'The username, email, or password you entered is incorrect. Please try again.', + description: 'Error message for incorrect email or password' + }, + loginIncorrectCredentialsErrorWithResetLink: { + id: 'login.incorrect.credentials.error.with.reset.link', + defaultMessage: 'The username, email, or password you entered is incorrect. Please try again or {resetLink}.', + description: 'Error message for incorrect email or password with multiple failure count' + }, + internalServerErrorMessage: { + id: 'internal.server.error.message', + defaultMessage: 'An error has occurred. Try refreshing the page, or check your internet connection.', + description: 'Error message that appears when server responds with 500 error code' + }, + loginIncorrectCredentialsErrorBeforeAccountBlockedText: { + id: 'login.incorrect.credentials.error.before.account.blocked.text', + defaultMessage: 'click here to reset it.', + description: 'Reset password link text for incorrect email or password credentials before blocking account' + }, + usernameOrEmailLessCharValidationMessage: { + id: 'username.or.email.format.validation.less.chars.message', + defaultMessage: 'Username or email must have at least 2 characters.', + description: 'Validation message that appears when username or email address is less than 2 characters' + }, + usernameOrEmailValidationMessage: { + id: 'email.validation.message', + defaultMessage: 'Enter your username or email', + description: 'Validation message that appears when email is empty' + }, + passwordValidationMessage: { + id: 'password.validation.message', + defaultMessage: 'Enter your password', + description: 'Validation message that appears when password is empty' + }, + nonCompliantPasswordTitle: { + id: 'non.compliant.password.title', + defaultMessage: 'We recently changed our password requirements', + description: 'A title that appears in bold before error message for non-compliant password' + }, + nonCompliantPasswordMessage: { + id: 'non.compliant.password.message', + defaultMessage: 'Your current password does not meet the new security requirements. ' + 'We just sent a password-reset message to the email address associated with this account. ' + 'Thank you for helping us keep your data safe.', + description: 'Error message for non-compliant password' + }, + // Email Confirmation Strings + accountConfirmationSuccessMessageTitle: { + id: 'account.confirmation.success.message.title', + defaultMessage: 'Success! You have confirmed your email.', + description: 'Account verification success message title' + }, + accountConfirmationSuccessMessage: { + id: 'account.confirmation.success.message', + defaultMessage: 'Sign in to continue.', + description: 'Message show to learners when their account has been activated successfully' + }, + accountConfirmationInfoMessage: { + id: 'account.confirmation.info.message', + defaultMessage: 'This email has already been confirmed.', + description: 'Message shown when learner account has already been verified' + }, + accountConfirmationErrorMessageTitle: { + id: 'account.confirmation.error.message.title', + defaultMessage: 'Your email could not be confirmed', + description: 'Account verification error message title' + }, + accountConfirmationSupportLink: { + id: 'account.confirmation.support.link', + defaultMessage: 'contact support', + description: 'Link text used in account confirmation error message to go to learner help center' + } +}); +export default messages; +//# sourceMappingURL=messages.js.map \ No newline at end of file diff --git a/dist/forms/login-popup/messages.js.map b/dist/forms/login-popup/messages.js.map new file mode 100644 index 00000000..21f6dea0 --- /dev/null +++ b/dist/forms/login-popup/messages.js.map @@ -0,0 +1 @@ +{"version":3,"file":"messages.js","names":["defineMessages","messages","loginFormHeading1","id","defaultMessage","description","loginFormSignInButton","loginFormForgotPasswordButton","loginFormRegistrationHelpText","loginFormRegistrationLink","loginFormSchoolAndOrganizationHelpText","loginFormSchoolAndOrganizationLink","loginFormEmailFieldLabel","loginFormPasswordFieldLabel","loginFormHeading2","loginFailureHeaderTitle","loginIncorrectCredentialsErrorResetLinkText","loginRateLimitReachedMessage","contactSupportLink","loginInactiveUserError","tpaAccountLink","allowedDomainLoginError","loginFormInvalidErrorMessage","loginIncorrectCredentialsErrorAttemptsText1","loginIncorrectCredentialsErrorAttemptsText2","accountLockedOutMessage1","accountLockedOutMessage2","loginIncorrectCredentialsError","loginIncorrectCredentialsErrorWithResetLink","internalServerErrorMessage","loginIncorrectCredentialsErrorBeforeAccountBlockedText","usernameOrEmailLessCharValidationMessage","usernameOrEmailValidationMessage","passwordValidationMessage","nonCompliantPasswordTitle","nonCompliantPasswordMessage","accountConfirmationSuccessMessageTitle","accountConfirmationSuccessMessage","accountConfirmationInfoMessage","accountConfirmationErrorMessageTitle","accountConfirmationSupportLink"],"sources":["../../../src/forms/login-popup/messages.js"],"sourcesContent":["import { defineMessages } from '@edx/frontend-platform/i18n';\n\nconst messages = defineMessages({\n loginFormHeading1: {\n id: 'login.form.heading.1',\n defaultMessage: 'Sign in',\n description: 'Login form main heading',\n },\n loginFormSignInButton: {\n id: 'login.form.signin.button.text',\n defaultMessage: 'Sign in',\n description: 'Sign in button label that appears on login page',\n },\n loginFormForgotPasswordButton: {\n id: 'login.form.forgot.password.button.text',\n defaultMessage: 'Forgot Password?',\n description: 'Button text for forgot password',\n },\n loginFormRegistrationHelpText: {\n id: 'login.form.sign.up.help.text',\n defaultMessage: 'Don’t have an account yet?',\n description: 'Sign up link help text',\n },\n loginFormRegistrationLink: {\n id: 'login.form.sign.up.link.text',\n defaultMessage: 'Create account',\n description: 'Text that appears on the registration button',\n },\n loginFormSchoolAndOrganizationHelpText: {\n id: 'login.form.school.and.organization.help.text',\n defaultMessage: 'Have an account through school or organization?',\n description: 'Label for school and organization login link',\n },\n loginFormSchoolAndOrganizationLink: {\n id: 'login.form.school.and.organization.link',\n defaultMessage: 'Sign in with your credentials',\n description: 'Text that appears on school and organization login link',\n },\n loginFormEmailFieldLabel: {\n id: 'login.form.email.field.label',\n defaultMessage: 'Email',\n description: 'Email field label',\n },\n loginFormPasswordFieldLabel: {\n id: 'login.form.password.field.label',\n defaultMessage: 'Password',\n description: 'Password field label',\n },\n loginFormHeading2: {\n id: 'login.form.heading.2',\n defaultMessage: 'or',\n description: 'Heading that appears between social auth and basic login form',\n },\n // error messages\n loginFailureHeaderTitle: {\n id: 'login.failure.header.title',\n defaultMessage: 'We couldn\\'t sign you in.',\n description: 'Login failure header message.',\n },\n loginIncorrectCredentialsErrorResetLinkText: {\n id: 'login.incorrect.credentials.error.reset.link.text',\n defaultMessage: 'reset your password',\n description: 'Reset password link text for incorrect email or password credentials',\n },\n loginRateLimitReachedMessage: {\n id: 'login.rate.limit.reached.message',\n defaultMessage: 'Too many failed login attempts. Try again later.',\n description: 'Error message that appears when an anonymous user has made too many failed login attempts',\n },\n contactSupportLink: {\n id: 'contact.support.link',\n defaultMessage: 'contact {platformName} support',\n description: 'Link text used in inactive user error message to go to learner help center',\n },\n loginInactiveUserError: {\n id: 'login.inactive.user.error',\n defaultMessage: 'In order to sign in, you need to activate your account.{lineBreak}{lineBreak}We just sent an activation link to {email}. If you do not receive an email, check your spam folders or {supportLink}.',\n description: 'Activation account message for inactive account',\n },\n tpaAccountLink: {\n id: 'tpa.account.link',\n defaultMessage: '{provider} account',\n description: 'Link text error message used to go to SSO when staff user try to login through password.',\n },\n allowedDomainLoginError: {\n id: 'allowed.domain.login.error',\n defaultMessage: 'As {allowedDomain} user, You must login with your {allowedDomain} {tpaLink}.',\n description: 'Display this error message when staff user try to login through password',\n },\n loginFormInvalidErrorMessage: {\n id: 'login.form.invalid.error.message',\n defaultMessage: 'Please fill in the fields below.',\n description: 'Login form empty input user message',\n },\n loginIncorrectCredentialsErrorAttemptsText1: {\n id: 'login.incorrect.credentials.error.attempts.text.1',\n defaultMessage: 'The username, email or password you entered is incorrect. You have {remainingAttempts} more sign in attempts before your account is temporarily locked.',\n description: 'Error message for incorrect email or password',\n },\n loginIncorrectCredentialsErrorAttemptsText2: {\n id: 'login.incorrect.credentials.error.attempts.text.2',\n defaultMessage: \"If you've forgotten your password, {resetLink}\",\n description: 'Part of error message for incorrect email or password',\n },\n accountLockedOutMessage1: {\n id: 'account.locked.out.message.1',\n defaultMessage: 'To protect your account, it\\'s been temporarily locked. Try again in 30 minutes.',\n description: 'Part of message for when user account has been locked out after multiple failed login attempts',\n },\n accountLockedOutMessage2: {\n id: 'account.locked.out.message.2',\n defaultMessage: 'To be on the safe side, you can {resetLink} before trying again.',\n description: 'Part of message for when user account has been locked out after multiple failed login attempts',\n },\n loginIncorrectCredentialsError: {\n id: 'login.incorrect.credentials.error',\n defaultMessage: 'The username, email, or password you entered is incorrect. Please try again.',\n description: 'Error message for incorrect email or password',\n },\n loginIncorrectCredentialsErrorWithResetLink: {\n id: 'login.incorrect.credentials.error.with.reset.link',\n defaultMessage: 'The username, email, or password you entered is incorrect. Please try again or {resetLink}.',\n description: 'Error message for incorrect email or password with multiple failure count',\n },\n internalServerErrorMessage: {\n id: 'internal.server.error.message',\n defaultMessage: 'An error has occurred. Try refreshing the page, or check your internet connection.',\n description: 'Error message that appears when server responds with 500 error code',\n },\n loginIncorrectCredentialsErrorBeforeAccountBlockedText: {\n id: 'login.incorrect.credentials.error.before.account.blocked.text',\n defaultMessage: 'click here to reset it.',\n description: 'Reset password link text for incorrect email or password credentials before blocking account',\n },\n usernameOrEmailLessCharValidationMessage: {\n id: 'username.or.email.format.validation.less.chars.message',\n defaultMessage: 'Username or email must have at least 2 characters.',\n description: 'Validation message that appears when username or email address is less than 2 characters',\n },\n usernameOrEmailValidationMessage: {\n id: 'email.validation.message',\n defaultMessage: 'Enter your username or email',\n description: 'Validation message that appears when email is empty',\n },\n passwordValidationMessage: {\n id: 'password.validation.message',\n defaultMessage: 'Enter your password',\n description: 'Validation message that appears when password is empty',\n },\n nonCompliantPasswordTitle: {\n id: 'non.compliant.password.title',\n defaultMessage: 'We recently changed our password requirements',\n description: 'A title that appears in bold before error message for non-compliant password',\n },\n nonCompliantPasswordMessage: {\n id: 'non.compliant.password.message',\n defaultMessage: 'Your current password does not meet the new security requirements. '\n + 'We just sent a password-reset message to the email address associated with this account. '\n + 'Thank you for helping us keep your data safe.',\n description: 'Error message for non-compliant password',\n },\n // Email Confirmation Strings\n accountConfirmationSuccessMessageTitle: {\n id: 'account.confirmation.success.message.title',\n defaultMessage: 'Success! You have confirmed your email.',\n description: 'Account verification success message title',\n },\n accountConfirmationSuccessMessage: {\n id: 'account.confirmation.success.message',\n defaultMessage: 'Sign in to continue.',\n description: 'Message show to learners when their account has been activated successfully',\n },\n accountConfirmationInfoMessage: {\n id: 'account.confirmation.info.message',\n defaultMessage: 'This email has already been confirmed.',\n description: 'Message shown when learner account has already been verified',\n },\n accountConfirmationErrorMessageTitle: {\n id: 'account.confirmation.error.message.title',\n defaultMessage: 'Your email could not be confirmed',\n description: 'Account verification error message title',\n },\n accountConfirmationSupportLink: {\n id: 'account.confirmation.support.link',\n defaultMessage: 'contact support',\n description: 'Link text used in account confirmation error message to go to learner help center',\n },\n});\n\nexport default messages;\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/progressive-profiling-popup/data/constants.js b/dist/forms/progressive-profiling-popup/data/constants.js new file mode 100644 index 00000000..8f3753d7 --- /dev/null +++ b/dist/forms/progressive-profiling-popup/data/constants.js @@ -0,0 +1,126 @@ +export const optionalFieldsData = { + subject: { + options: [] + }, + levelOfEducation: { + options: [{ + label: 'none' + }, { + label: 'jhs' + }, { + label: 'hs' + }, { + label: 'a' + }, { + label: 'b' + }, { + label: 'm' + }, { + label: 'p' + }, { + label: 'other' + }] + }, + workExperience: { + options: [{ + label: '0yrs' + }, { + label: '1-5yrs' + }, { + label: '6-10yrs' + }, { + label: '11-15yrs' + }, { + label: '16-20yrs' + }, { + label: '20+yrs' + }] + }, + learningType: { + options: [{ + label: 'Courses' + }, { + label: 'Boot Camps' + }, { + label: 'Degrees' + }, { + label: 'Executive Education' + }, { + label: 'unsure' + }] + }, + gender: { + options: [{ + label: 'm' + }, { + label: 'f' + }, { + label: 'o' + }] + } +}; +export const defaultSubjectList = [{ + name: 'Business & Management' +}, { + name: 'Computer Science' +}, { + name: 'Engineering' +}, { + name: 'Social Sciences' +}, { + name: 'Data Analysis & Statistics' +}, { + name: 'Economics & Finance' +}, { + name: 'Communication' +}, { + name: 'Humanities' +}, { + name: 'Science' +}, { + name: 'Environmental Studies' +}, { + name: 'Medicine' +}, { + name: 'Biology & Life Sciences' +}, { + name: 'Health & Safety' +}, { + name: 'Education & Teacher Training' +}, { + name: 'Art & Culture' +}, { + name: 'Math' +}, { + name: 'History' +}, { + name: 'Design' +}, { + name: 'Physics' +}, { + name: 'Energy & Earth Sciences' +}, { + name: 'Law' +}, { + name: 'Philosophy & Ethics' +}, { + name: 'Language' +}, { + name: 'Electronics' +}, { + name: 'Food & Nutrition' +}, { + name: 'Architecture' +}, { + name: 'Chemistry' +}, { + name: 'Literature' +}, { + name: 'Ethics' +}, { + name: 'Music' +}, { + name: 'Philanthropy' +}]; +export const extendedProfileFields = ['subject', 'workExperience', 'learningType']; +//# sourceMappingURL=constants.js.map \ No newline at end of file diff --git a/dist/forms/progressive-profiling-popup/data/constants.js.map b/dist/forms/progressive-profiling-popup/data/constants.js.map new file mode 100644 index 00000000..00f031ce --- /dev/null +++ b/dist/forms/progressive-profiling-popup/data/constants.js.map @@ -0,0 +1 @@ +{"version":3,"file":"constants.js","names":["optionalFieldsData","subject","options","levelOfEducation","label","workExperience","learningType","gender","defaultSubjectList","name","extendedProfileFields"],"sources":["../../../../src/forms/progressive-profiling-popup/data/constants.js"],"sourcesContent":["export const optionalFieldsData = {\n subject: {\n options: [],\n },\n levelOfEducation: {\n options: [\n {\n label: 'none',\n },\n {\n label: 'jhs',\n },\n {\n label: 'hs',\n },\n {\n label: 'a',\n },\n {\n label: 'b',\n },\n {\n label: 'm',\n },\n {\n label: 'p',\n },\n {\n label: 'other',\n },\n ],\n },\n workExperience: {\n options: [\n {\n label: '0yrs',\n },\n {\n label: '1-5yrs',\n },\n {\n label: '6-10yrs',\n },\n {\n label: '11-15yrs',\n },\n {\n label: '16-20yrs',\n },\n {\n label: '20+yrs',\n },\n ],\n },\n learningType: {\n options: [\n {\n label: 'Courses',\n },\n {\n label: 'Boot Camps',\n },\n {\n label: 'Degrees',\n },\n {\n label: 'Executive Education',\n },\n {\n label: 'unsure',\n },\n ],\n },\n gender: {\n options: [\n {\n label: 'm',\n },\n {\n label: 'f',\n },\n {\n label: 'o',\n },\n ],\n },\n};\n\nexport const defaultSubjectList = [\n {\n name: 'Business & Management',\n },\n {\n name: 'Computer Science',\n },\n {\n name: 'Engineering',\n },\n {\n name: 'Social Sciences',\n },\n {\n name: 'Data Analysis & Statistics',\n },\n {\n name: 'Economics & Finance',\n },\n {\n name: 'Communication',\n },\n {\n name: 'Humanities',\n },\n {\n name: 'Science',\n },\n {\n name: 'Environmental Studies',\n },\n {\n name: 'Medicine',\n },\n {\n name: 'Biology & Life Sciences',\n },\n {\n name: 'Health & Safety',\n },\n {\n name: 'Education & Teacher Training',\n },\n {\n name: 'Art & Culture',\n },\n {\n name: 'Math',\n },\n {\n name: 'History',\n },\n {\n name: 'Design',\n },\n {\n name: 'Physics',\n },\n {\n name: 'Energy & Earth Sciences',\n },\n {\n name: 'Law',\n },\n {\n name: 'Philosophy & Ethics',\n },\n {\n name: 'Language',\n },\n {\n name: 'Electronics',\n },\n {\n name: 'Food & Nutrition',\n },\n {\n name: 'Architecture',\n },\n {\n name: 'Chemistry',\n },\n {\n name: 'Literature',\n },\n {\n name: 'Ethics',\n },\n {\n name: 'Music',\n },\n {\n name: 'Philanthropy',\n },\n];\n\nexport const extendedProfileFields = ['subject', 'workExperience', 'learningType'];\n"],"mappings":"AAAA,OAAO,MAAMA,kBAAkB,GAAG;EAChCC,OAAO,EAAE;IACPC,OAAO,EAAE;EACX,CAAC;EACDC,gBAAgB,EAAE;IAChBD,OAAO,EAAE,CACP;MACEE,KAAK,EAAE;IACT,CAAC,EACD;MACEA,KAAK,EAAE;IACT,CAAC,EACD;MACEA,KAAK,EAAE;IACT,CAAC,EACD;MACEA,KAAK,EAAE;IACT,CAAC,EACD;MACEA,KAAK,EAAE;IACT,CAAC,EACD;MACEA,KAAK,EAAE;IACT,CAAC,EACD;MACEA,KAAK,EAAE;IACT,CAAC,EACD;MACEA,KAAK,EAAE;IACT,CAAC;EAEL,CAAC;EACDC,cAAc,EAAE;IACdH,OAAO,EAAE,CACP;MACEE,KAAK,EAAE;IACT,CAAC,EACD;MACEA,KAAK,EAAE;IACT,CAAC,EACD;MACEA,KAAK,EAAE;IACT,CAAC,EACD;MACEA,KAAK,EAAE;IACT,CAAC,EACD;MACEA,KAAK,EAAE;IACT,CAAC,EACD;MACEA,KAAK,EAAE;IACT,CAAC;EAEL,CAAC;EACDE,YAAY,EAAE;IACZJ,OAAO,EAAE,CACP;MACEE,KAAK,EAAE;IACT,CAAC,EACD;MACEA,KAAK,EAAE;IACT,CAAC,EACD;MACEA,KAAK,EAAE;IACT,CAAC,EACD;MACEA,KAAK,EAAE;IACT,CAAC,EACD;MACEA,KAAK,EAAE;IACT,CAAC;EAEL,CAAC;EACDG,MAAM,EAAE;IACNL,OAAO,EAAE,CACP;MACEE,KAAK,EAAE;IACT,CAAC,EACD;MACEA,KAAK,EAAE;IACT,CAAC,EACD;MACEA,KAAK,EAAE;IACT,CAAC;EAEL;AACF,CAAC;AAED,OAAO,MAAMI,kBAAkB,GAAG,CAChC;EACEC,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,EACD;EACEA,IAAI,EAAE;AACR,CAAC,CACF;AAED,OAAO,MAAMC,qBAAqB,GAAG,CAAC,SAAS,EAAE,gBAAgB,EAAE,cAAc,CAAC","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/progressive-profiling-popup/data/hooks/useSubjectList.js b/dist/forms/progressive-profiling-popup/data/hooks/useSubjectList.js new file mode 100644 index 00000000..d18a6363 --- /dev/null +++ b/dist/forms/progressive-profiling-popup/data/hooks/useSubjectList.js @@ -0,0 +1,45 @@ +import { useEffect, useState } from 'react'; +import { getConfig } from '@edx/frontend-platform'; +import algoliasearch from 'algoliasearch'; +import algoliasearchHelper from 'algoliasearch-helper'; +import { defaultSubjectList } from '../constants'; +const PRODUCT_INDEX = 'product'; +const SUBJECT_FACET = 'subject'; +const getAlgoliaSearchClient = () => algoliasearch(getConfig().AUTHN_ALGOLIA_APP_ID, getConfig().AUTHN_ALGOLIA_SEARCH_API_KEY); +const parseSubjectsFromAlgoliaResults = subjectsList => subjectsList.map(subject => ({ + label: subject.name +})); +const useSubjectsList = () => { + const [subjectsList, setSubjectsList] = useState([]); + const [subjectsLoading, setSubjectsLoading] = useState(true); + useEffect(() => { + const searchClient = getAlgoliaSearchClient(); + const searchHelper = algoliasearchHelper(searchClient, PRODUCT_INDEX, { + facets: [SUBJECT_FACET] + }); + const searchIndex = () => { + setSubjectsLoading(true); + searchHelper.search(); + }; + searchIndex(); + searchHelper.on('result', _ref => { + let { + results + } = _ref; + setSubjectsList(parseSubjectsFromAlgoliaResults(results.getFacetValues(SUBJECT_FACET, {}))); + setSubjectsLoading(false); + }); + searchHelper.on('error', () => { + setSubjectsLoading(false); + setSubjectsList(parseSubjectsFromAlgoliaResults(defaultSubjectList)); + }); + }, []); + return { + subjectsList: { + options: subjectsList + }, + subjectsLoading + }; +}; +export default useSubjectsList; +//# sourceMappingURL=useSubjectList.js.map \ No newline at end of file diff --git a/dist/forms/progressive-profiling-popup/data/hooks/useSubjectList.js.map b/dist/forms/progressive-profiling-popup/data/hooks/useSubjectList.js.map new file mode 100644 index 00000000..eff8cec4 --- /dev/null +++ b/dist/forms/progressive-profiling-popup/data/hooks/useSubjectList.js.map @@ -0,0 +1 @@ +{"version":3,"file":"useSubjectList.js","names":["useEffect","useState","getConfig","algoliasearch","algoliasearchHelper","defaultSubjectList","PRODUCT_INDEX","SUBJECT_FACET","getAlgoliaSearchClient","AUTHN_ALGOLIA_APP_ID","AUTHN_ALGOLIA_SEARCH_API_KEY","parseSubjectsFromAlgoliaResults","subjectsList","map","subject","label","name","useSubjectsList","setSubjectsList","subjectsLoading","setSubjectsLoading","searchClient","searchHelper","facets","searchIndex","search","on","_ref","results","getFacetValues","options"],"sources":["../../../../../src/forms/progressive-profiling-popup/data/hooks/useSubjectList.jsx"],"sourcesContent":["import { useEffect, useState } from 'react';\n\nimport { getConfig } from '@edx/frontend-platform';\nimport algoliasearch from 'algoliasearch';\nimport algoliasearchHelper from 'algoliasearch-helper';\n\nimport { defaultSubjectList } from '../constants';\n\nconst PRODUCT_INDEX = 'product';\nconst SUBJECT_FACET = 'subject';\n\nconst getAlgoliaSearchClient = () => algoliasearch(\n getConfig().AUTHN_ALGOLIA_APP_ID,\n getConfig().AUTHN_ALGOLIA_SEARCH_API_KEY,\n);\n\nconst parseSubjectsFromAlgoliaResults = (subjectsList) => (\n subjectsList.map(subject => ({ label: subject.name }))\n);\n\nconst useSubjectsList = () => {\n const [subjectsList, setSubjectsList] = useState([]);\n const [subjectsLoading, setSubjectsLoading] = useState(true);\n\n useEffect(() => {\n const searchClient = getAlgoliaSearchClient();\n const searchHelper = algoliasearchHelper(\n searchClient,\n PRODUCT_INDEX,\n { facets: [SUBJECT_FACET] },\n );\n\n const searchIndex = () => {\n setSubjectsLoading(true);\n searchHelper.search();\n };\n\n searchIndex();\n\n searchHelper.on('result', ({ results }) => {\n setSubjectsList(parseSubjectsFromAlgoliaResults(results.getFacetValues(SUBJECT_FACET, {})));\n setSubjectsLoading(false);\n });\n\n searchHelper.on('error', () => {\n setSubjectsLoading(false);\n setSubjectsList(parseSubjectsFromAlgoliaResults(defaultSubjectList));\n });\n }, []);\n\n return {\n subjectsList: {\n options: subjectsList,\n },\n subjectsLoading,\n };\n};\n\nexport default useSubjectsList;\n"],"mappings":"AAAA,SAASA,SAAS,EAAEC,QAAQ,QAAQ,OAAO;AAE3C,SAASC,SAAS,QAAQ,wBAAwB;AAClD,OAAOC,aAAa,MAAM,eAAe;AACzC,OAAOC,mBAAmB,MAAM,sBAAsB;AAEtD,SAASC,kBAAkB,QAAQ,cAAc;AAEjD,MAAMC,aAAa,GAAG,SAAS;AAC/B,MAAMC,aAAa,GAAG,SAAS;AAE/B,MAAMC,sBAAsB,GAAGA,CAAA,KAAML,aAAa,CAChDD,SAAS,CAAC,CAAC,CAACO,oBAAoB,EAChCP,SAAS,CAAC,CAAC,CAACQ,4BACd,CAAC;AAED,MAAMC,+BAA+B,GAAIC,YAAY,IACnDA,YAAY,CAACC,GAAG,CAACC,OAAO,KAAK;EAAEC,KAAK,EAAED,OAAO,CAACE;AAAK,CAAC,CAAC,CACtD;AAED,MAAMC,eAAe,GAAGA,CAAA,KAAM;EAC5B,MAAM,CAACL,YAAY,EAAEM,eAAe,CAAC,GAAGjB,QAAQ,CAAC,EAAE,CAAC;EACpD,MAAM,CAACkB,eAAe,EAAEC,kBAAkB,CAAC,GAAGnB,QAAQ,CAAC,IAAI,CAAC;EAE5DD,SAAS,CAAC,MAAM;IACd,MAAMqB,YAAY,GAAGb,sBAAsB,CAAC,CAAC;IAC7C,MAAMc,YAAY,GAAGlB,mBAAmB,CACtCiB,YAAY,EACZf,aAAa,EACb;MAAEiB,MAAM,EAAE,CAAChB,aAAa;IAAE,CAC5B,CAAC;IAED,MAAMiB,WAAW,GAAGA,CAAA,KAAM;MACxBJ,kBAAkB,CAAC,IAAI,CAAC;MACxBE,YAAY,CAACG,MAAM,CAAC,CAAC;IACvB,CAAC;IAEDD,WAAW,CAAC,CAAC;IAEbF,YAAY,CAACI,EAAE,CAAC,QAAQ,EAAEC,IAAA,IAAiB;MAAA,IAAhB;QAAEC;MAAQ,CAAC,GAAAD,IAAA;MACpCT,eAAe,CAACP,+BAA+B,CAACiB,OAAO,CAACC,cAAc,CAACtB,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;MAC3Fa,kBAAkB,CAAC,KAAK,CAAC;IAC3B,CAAC,CAAC;IAEFE,YAAY,CAACI,EAAE,CAAC,OAAO,EAAE,MAAM;MAC7BN,kBAAkB,CAAC,KAAK,CAAC;MACzBF,eAAe,CAACP,+BAA+B,CAACN,kBAAkB,CAAC,CAAC;IACtE,CAAC,CAAC;EACJ,CAAC,EAAE,EAAE,CAAC;EAEN,OAAO;IACLO,YAAY,EAAE;MACZkB,OAAO,EAAElB;IACX,CAAC;IACDO;EACF,CAAC;AACH,CAAC;AAED,eAAeF,eAAe","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/progressive-profiling-popup/data/reducers.js b/dist/forms/progressive-profiling-popup/data/reducers.js new file mode 100644 index 00000000..12775bd2 --- /dev/null +++ b/dist/forms/progressive-profiling-popup/data/reducers.js @@ -0,0 +1,51 @@ +/** + * Redux slice for managing progressiveProfiling state. + * This slice handles the progressiveProfiling process, including the submission state, + * progressiveProfiling success and progressiveProfiling failure. + */ + +import { createSlice } from '@reduxjs/toolkit'; +import { COMPLETE_STATE, DEFAULT_STATE, FAILURE_STATE, PENDING_STATE } from '../../../data/constants'; +export const storeName = 'progressiveProfiling'; +export const PROGRESSIVE_PROFILING_SLICE_NAME = 'progressiveProfiling'; +export const progressiveProfilingInitialState = { + submitState: DEFAULT_STATE, + redirectUrl: '', + subjectsList: {} +}; +export const progressiveProfilingSlice = createSlice({ + name: PROGRESSIVE_PROFILING_SLICE_NAME, + initialState: progressiveProfilingInitialState, + reducers: { + saveUserProfile: state => { + state.submitState = PENDING_STATE; + }, + saveUserProfileSuccess: state => { + state.submitState = COMPLETE_STATE; + }, + saveUserProfileFailure: state => { + state.submitState = FAILURE_STATE; + }, + setProgressiveProfilingRedirectUrl: (state, _ref) => { + let { + payload: redirectUrl + } = _ref; + state.redirectUrl = redirectUrl; + }, + setSubjectsList: (state, _ref2) => { + let { + payload + } = _ref2; + state.subjectsList = payload; + } + } +}); +export const { + saveUserProfile, + saveUserProfileSuccess, + saveUserProfileFailure, + setProgressiveProfilingRedirectUrl, + setSubjectsList +} = progressiveProfilingSlice.actions; +export default progressiveProfilingSlice.reducer; +//# sourceMappingURL=reducers.js.map \ No newline at end of file diff --git a/dist/forms/progressive-profiling-popup/data/reducers.js.map b/dist/forms/progressive-profiling-popup/data/reducers.js.map new file mode 100644 index 00000000..a32b176e --- /dev/null +++ b/dist/forms/progressive-profiling-popup/data/reducers.js.map @@ -0,0 +1 @@ +{"version":3,"file":"reducers.js","names":["createSlice","COMPLETE_STATE","DEFAULT_STATE","FAILURE_STATE","PENDING_STATE","storeName","PROGRESSIVE_PROFILING_SLICE_NAME","progressiveProfilingInitialState","submitState","redirectUrl","subjectsList","progressiveProfilingSlice","name","initialState","reducers","saveUserProfile","state","saveUserProfileSuccess","saveUserProfileFailure","setProgressiveProfilingRedirectUrl","_ref","payload","setSubjectsList","_ref2","actions","reducer"],"sources":["../../../../src/forms/progressive-profiling-popup/data/reducers.js"],"sourcesContent":["/**\n * Redux slice for managing progressiveProfiling state.\n * This slice handles the progressiveProfiling process, including the submission state,\n * progressiveProfiling success and progressiveProfiling failure.\n */\n\nimport { createSlice } from '@reduxjs/toolkit';\n\nimport {\n COMPLETE_STATE,\n DEFAULT_STATE,\n FAILURE_STATE,\n PENDING_STATE,\n} from '../../../data/constants';\n\nexport const storeName = 'progressiveProfiling';\nexport const PROGRESSIVE_PROFILING_SLICE_NAME = 'progressiveProfiling';\n\nexport const progressiveProfilingInitialState = {\n submitState: DEFAULT_STATE,\n redirectUrl: '',\n subjectsList: {},\n};\n\nexport const progressiveProfilingSlice = createSlice({\n name: PROGRESSIVE_PROFILING_SLICE_NAME,\n initialState: progressiveProfilingInitialState,\n reducers: {\n saveUserProfile: (state) => {\n state.submitState = PENDING_STATE;\n },\n saveUserProfileSuccess: (state) => {\n state.submitState = COMPLETE_STATE;\n },\n saveUserProfileFailure: (state) => {\n state.submitState = FAILURE_STATE;\n },\n setProgressiveProfilingRedirectUrl: (state, { payload: redirectUrl }) => {\n state.redirectUrl = redirectUrl;\n },\n setSubjectsList: (state, { payload }) => {\n state.subjectsList = payload;\n },\n },\n});\n\nexport const {\n saveUserProfile,\n saveUserProfileSuccess,\n saveUserProfileFailure,\n setProgressiveProfilingRedirectUrl,\n setSubjectsList,\n} = progressiveProfilingSlice.actions;\n\nexport default progressiveProfilingSlice.reducer;\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;;AAEA,SAASA,WAAW,QAAQ,kBAAkB;AAE9C,SACEC,cAAc,EACdC,aAAa,EACbC,aAAa,EACbC,aAAa,QACR,yBAAyB;AAEhC,OAAO,MAAMC,SAAS,GAAG,sBAAsB;AAC/C,OAAO,MAAMC,gCAAgC,GAAG,sBAAsB;AAEtE,OAAO,MAAMC,gCAAgC,GAAG;EAC9CC,WAAW,EAAEN,aAAa;EAC1BO,WAAW,EAAE,EAAE;EACfC,YAAY,EAAE,CAAC;AACjB,CAAC;AAED,OAAO,MAAMC,yBAAyB,GAAGX,WAAW,CAAC;EACnDY,IAAI,EAAEN,gCAAgC;EACtCO,YAAY,EAAEN,gCAAgC;EAC9CO,QAAQ,EAAE;IACRC,eAAe,EAAGC,KAAK,IAAK;MAC1BA,KAAK,CAACR,WAAW,GAAGJ,aAAa;IACnC,CAAC;IACDa,sBAAsB,EAAGD,KAAK,IAAK;MACjCA,KAAK,CAACR,WAAW,GAAGP,cAAc;IACpC,CAAC;IACDiB,sBAAsB,EAAGF,KAAK,IAAK;MACjCA,KAAK,CAACR,WAAW,GAAGL,aAAa;IACnC,CAAC;IACDgB,kCAAkC,EAAEA,CAACH,KAAK,EAAAI,IAAA,KAA+B;MAAA,IAA7B;QAAEC,OAAO,EAAEZ;MAAY,CAAC,GAAAW,IAAA;MAClEJ,KAAK,CAACP,WAAW,GAAGA,WAAW;IACjC,CAAC;IACDa,eAAe,EAAEA,CAACN,KAAK,EAAAO,KAAA,KAAkB;MAAA,IAAhB;QAAEF;MAAQ,CAAC,GAAAE,KAAA;MAClCP,KAAK,CAACN,YAAY,GAAGW,OAAO;IAC9B;EACF;AACF,CAAC,CAAC;AAEF,OAAO,MAAM;EACXN,eAAe;EACfE,sBAAsB;EACtBC,sBAAsB;EACtBC,kCAAkC;EAClCG;AACF,CAAC,GAAGX,yBAAyB,CAACa,OAAO;AAErC,eAAeb,yBAAyB,CAACc,OAAO","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/progressive-profiling-popup/data/sagas.js b/dist/forms/progressive-profiling-popup/data/sagas.js new file mode 100644 index 00000000..9fb8e77b --- /dev/null +++ b/dist/forms/progressive-profiling-popup/data/sagas.js @@ -0,0 +1,22 @@ +import { logError } from '@edx/frontend-platform/logging'; +import { call, put, takeEvery } from 'redux-saga/effects'; +import { saveUserProfile, saveUserProfileFailure, saveUserProfileSuccess } from './reducers'; +import patchAccount from './services'; + +/** + * Saga function for handling save user profile. + * @param {object} action - The Redux action object containing the payload. + */ +export function* handleSaveUserProfile(action) { + try { + yield call(patchAccount, action.payload.username, action.payload.data); + yield put(saveUserProfileSuccess()); + } catch (e) { + yield put(saveUserProfileFailure()); + logError(e); + } +} +export default function* saga() { + yield takeEvery(saveUserProfile.type, handleSaveUserProfile); +} +//# sourceMappingURL=sagas.js.map \ No newline at end of file diff --git a/dist/forms/progressive-profiling-popup/data/sagas.js.map b/dist/forms/progressive-profiling-popup/data/sagas.js.map new file mode 100644 index 00000000..d05b4d55 --- /dev/null +++ b/dist/forms/progressive-profiling-popup/data/sagas.js.map @@ -0,0 +1 @@ +{"version":3,"file":"sagas.js","names":["logError","call","put","takeEvery","saveUserProfile","saveUserProfileFailure","saveUserProfileSuccess","patchAccount","handleSaveUserProfile","action","payload","username","data","e","saga","type"],"sources":["../../../../src/forms/progressive-profiling-popup/data/sagas.js"],"sourcesContent":["import { logError } from '@edx/frontend-platform/logging';\nimport { call, put, takeEvery } from 'redux-saga/effects';\n\nimport {\n saveUserProfile,\n saveUserProfileFailure,\n saveUserProfileSuccess,\n} from './reducers';\nimport patchAccount from './services';\n\n/**\n * Saga function for handling save user profile.\n * @param {object} action - The Redux action object containing the payload.\n */\nexport function* handleSaveUserProfile(action) {\n try {\n yield call(patchAccount, action.payload.username, action.payload.data);\n\n yield put(saveUserProfileSuccess());\n } catch (e) {\n yield put(saveUserProfileFailure());\n logError(e);\n }\n}\n\nexport default function* saga() {\n yield takeEvery(saveUserProfile.type, handleSaveUserProfile);\n}\n"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,gCAAgC;AACzD,SAASC,IAAI,EAAEC,GAAG,EAAEC,SAAS,QAAQ,oBAAoB;AAEzD,SACEC,eAAe,EACfC,sBAAsB,EACtBC,sBAAsB,QACjB,YAAY;AACnB,OAAOC,YAAY,MAAM,YAAY;;AAErC;AACA;AACA;AACA;AACA,OAAO,UAAUC,qBAAqBA,CAACC,MAAM,EAAE;EAC7C,IAAI;IACF,MAAMR,IAAI,CAACM,YAAY,EAAEE,MAAM,CAACC,OAAO,CAACC,QAAQ,EAAEF,MAAM,CAACC,OAAO,CAACE,IAAI,CAAC;IAEtE,MAAMV,GAAG,CAACI,sBAAsB,CAAC,CAAC,CAAC;EACrC,CAAC,CAAC,OAAOO,CAAC,EAAE;IACV,MAAMX,GAAG,CAACG,sBAAsB,CAAC,CAAC,CAAC;IACnCL,QAAQ,CAACa,CAAC,CAAC;EACb;AACF;AAEA,eAAe,UAAUC,IAAIA,CAAA,EAAG;EAC9B,MAAMX,SAAS,CAACC,eAAe,CAACW,IAAI,EAAEP,qBAAqB,CAAC;AAC9D","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/progressive-profiling-popup/data/services.js b/dist/forms/progressive-profiling-popup/data/services.js new file mode 100644 index 00000000..d611465d --- /dev/null +++ b/dist/forms/progressive-profiling-popup/data/services.js @@ -0,0 +1,26 @@ +import { getConfig } from '@edx/frontend-platform'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; + +/** + * Function for making a account request to the server. + * This function sends a PATCH request to the account endpoint with the provided payload. + * @param {object} payload - The payload to be sent to the server. + * @param {string} username - username will be used to prepare the accounts URL + * @returns {object} An object containing the response status. + */ +export default async function patchAccount(username, payload) { + const requestConfig = { + headers: { + 'Content-Type': 'application/merge-patch+json' + } + }; + const { + status + } = await getAuthenticatedHttpClient().patch(`${getConfig().LMS_BASE_URL}/api/user/v1/accounts/${username}`, payload, requestConfig).catch(error => { + throw error; + }); + return { + status + }; +} +//# sourceMappingURL=services.js.map \ No newline at end of file diff --git a/dist/forms/progressive-profiling-popup/data/services.js.map b/dist/forms/progressive-profiling-popup/data/services.js.map new file mode 100644 index 00000000..19a456d9 --- /dev/null +++ b/dist/forms/progressive-profiling-popup/data/services.js.map @@ -0,0 +1 @@ +{"version":3,"file":"services.js","names":["getConfig","getAuthenticatedHttpClient","patchAccount","username","payload","requestConfig","headers","status","patch","LMS_BASE_URL","catch","error"],"sources":["../../../../src/forms/progressive-profiling-popup/data/services.js"],"sourcesContent":["import { getConfig } from '@edx/frontend-platform';\nimport { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';\n\n/**\n * Function for making a account request to the server.\n * This function sends a PATCH request to the account endpoint with the provided payload.\n * @param {object} payload - The payload to be sent to the server.\n * @param {string} username - username will be used to prepare the accounts URL\n * @returns {object} An object containing the response status.\n */\nexport default async function patchAccount(username, payload) {\n const requestConfig = {\n headers: { 'Content-Type': 'application/merge-patch+json' },\n };\n\n const { status } = await getAuthenticatedHttpClient()\n .patch(\n `${getConfig().LMS_BASE_URL}/api/user/v1/accounts/${username}`,\n payload,\n requestConfig,\n )\n .catch((error) => {\n throw (error);\n });\n return { status };\n}\n"],"mappings":"AAAA,SAASA,SAAS,QAAQ,wBAAwB;AAClD,SAASC,0BAA0B,QAAQ,6BAA6B;;AAExE;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,eAAeC,YAAYA,CAACC,QAAQ,EAAEC,OAAO,EAAE;EAC5D,MAAMC,aAAa,GAAG;IACpBC,OAAO,EAAE;MAAE,cAAc,EAAE;IAA+B;EAC5D,CAAC;EAED,MAAM;IAAEC;EAAO,CAAC,GAAG,MAAMN,0BAA0B,CAAC,CAAC,CAClDO,KAAK,CACH,GAAER,SAAS,CAAC,CAAC,CAACS,YAAa,yBAAwBN,QAAS,EAAC,EAC9DC,OAAO,EACPC,aACF,CAAC,CACAK,KAAK,CAAEC,KAAK,IAAK;IAChB,MAAOA,KAAK;EACd,CAAC,CAAC;EACJ,OAAO;IAAEJ;EAAO,CAAC;AACnB","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/progressive-profiling-popup/index.js b/dist/forms/progressive-profiling-popup/index.js new file mode 100644 index 00000000..59b6197b --- /dev/null +++ b/dist/forms/progressive-profiling-popup/index.js @@ -0,0 +1,319 @@ +function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } +function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } +function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); } +function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { getConfig, snakeCaseObject } from '@edx/frontend-platform'; +import { identifyAuthenticatedUser } from '@edx/frontend-platform/analytics'; +import { AxiosJwtAuthService, configure as configureAuth } from '@edx/frontend-platform/auth'; +import { getCountryList, getLocale, useIntl } from '@edx/frontend-platform/i18n'; +import { getLoggingService } from '@edx/frontend-platform/logging'; +import { Container, Form, Icon, StatefulButton } from '@openedx/paragon'; +import { Language } from '@openedx/paragon/icons'; +import { extendedProfileFields, optionalFieldsData } from './data/constants'; +import { saveUserProfile } from './data/reducers'; +import messages from './messages'; +import { setCurrentOpenedForm } from '../../authn-component/data/reducers'; +import { COMPLETE_STATE, DEFAULT_STATE, FAILURE_STATE, LOGIN_FORM, PENDING_STATE } from '../../data/constants'; +import { useDispatch, useSelector } from '../../data/storeHooks'; +import { getCountryCookieValue, moveScrollToTop } from '../../data/utils'; +import { trackProgressiveProfilingPageViewed, trackProgressiveProfilingSkipLinkClick, trackProgressiveProfilingSubmitClick } from '../../tracking/trackers/progressive-profiling'; +import AuthenticatedRedirection from '../common-components/AuthenticatedRedirection'; +import AutoSuggestField from '../fields/auto-suggested-field'; +import './index.scss'; + +/** + * Progressive profiling form component. This component holds the logic to render optional demographic + * form fields and infor users about the auto-generated country field. + * + * @returns {JSX.Element} Progressive profiling form rendered inside BaseContainer component. + */ +const ProgressiveProfilingForm = () => { + const { + formatMessage + } = useIntl(); + const dispatch = useDispatch(); + const countryFieldRef = useRef(null); + const countryCookieValue = getCountryCookieValue(); + const countryList = useMemo(() => getCountryList(getLocale()), []); + const submitState = useSelector(state => state.progressiveProfiling.submitState); + const subjectsList = useSelector(state => state.progressiveProfiling.subjectsList); + const redirectUrl = useSelector(state => state.progressiveProfiling.redirectUrl); + const authContextCountryCode = useSelector(state => state.commonData.thirdPartyAuthContext.countryCode); + const finishAuthUrl = useSelector(state => state.commonData.thirdPartyAuthContext.finishAuthUrl); + const authenticatedUser = useSelector(state => state.register.registrationResult.authenticatedUser); + const [formData, setFormData] = useState({}); + const [formErrors, setFormErrors] = useState({}); + const [autoFilledCountry, setAutoFilledCountry] = useState({ + value: '', + displayText: '' + }); + const [skipButtonState, setSkipButtonState] = useState(DEFAULT_STATE); + useEffect(() => { + let countryCode = null; + if (countryCookieValue) { + countryCode = countryCookieValue; + } else if (authContextCountryCode) { + countryCode = authContextCountryCode; + } + if (!countryCode) { + return; + } + const userCountry = countryList.find(country => country.code === countryCode); + if (userCountry?.code !== '' && autoFilledCountry.value === '') { + setAutoFilledCountry({ + value: userCountry?.code, + displayText: userCountry?.name + }); + // set formData state for auto populated country field to pass into payload + setFormData({ + country: userCountry?.code + }); + } + }, [authContextCountryCode, autoFilledCountry, countryCookieValue, countryList, formatMessage]); + useEffect(() => { + if (authenticatedUser === null) { + dispatch(setCurrentOpenedForm(LOGIN_FORM)); + } + if (authenticatedUser?.userId) { + identifyAuthenticatedUser(authenticatedUser?.userId); + configureAuth(AxiosJwtAuthService, { + loggingService: getLoggingService(), + config: getConfig() + }); + trackProgressiveProfilingPageViewed(); + } + }, [authenticatedUser, dispatch]); + const hasFormErrors = () => { + let error = false; + if (!('country' in formData) || formData?.country === '') { + setFormErrors(_objectSpread(_objectSpread({}, formErrors), {}, { + country: formatMessage(messages.progressiveProfilingCountryFieldErrorMessage) + })); + error = true; + } + return error; + }; + const handleSelect = e => { + const { + name, + value, + text + } = e.target; + if (text === '') { + setFormErrors(_objectSpread(_objectSpread({}, formErrors), {}, { + [name]: formatMessage(messages.progressiveProfilingCountryFieldErrorMessage) + })); + } else if (value) { + setFormErrors(_objectSpread(_objectSpread({}, formErrors), {}, { + [name]: '' + })); + } + setFormData(_objectSpread(_objectSpread({}, formData), {}, { + [name]: value + })); + }; + const radioButtonOnChangeHandler = e => { + const { + name, + value + } = e.target; + setFormData(_objectSpread(_objectSpread({}, formData), {}, { + [name]: value + })); + }; + const onFieldFocus = e => { + const { + name, + value + } = e.target; + setFormErrors(_objectSpread(_objectSpread({}, formErrors), {}, { + [name]: value + })); + }; + const onFieldBlur = e => { + const { + name, + value + } = e.target; + if (value === '') { + setFormErrors(_objectSpread(_objectSpread({}, formErrors), {}, { + [name]: formatMessage(messages.progressiveProfilingCountryFieldErrorMessage) + })); + } + }; + const handleSubmit = e => { + e.preventDefault(); + if (hasFormErrors()) { + moveScrollToTop(countryFieldRef); + return; + } + const eventProperties = { + isGenderSelected: !!formData.gender, + isLevelOfEducationSelected: !!formData.levelOfEducation, + isWorkExperienceSelected: !!formData.workExperience, + isSubjectSelected: !!formData.subject, + isLearningTypeSelected: !!formData.learningType + }; + const extendedProfile = []; + if (Object.keys(formData).length > 0) { + Object.keys(formData).forEach(fieldName => { + if (extendedProfileFields.includes(fieldName)) { + extendedProfile.push({ + fieldName, + fieldValue: formData[fieldName] + }); + delete formData[fieldName]; + } + }); + } + const payload = { + username: authenticatedUser?.username, + data: _objectSpread({ + extendedProfile + }, formData) + }; + trackProgressiveProfilingSubmitClick(eventProperties); + dispatch(saveUserProfile(snakeCaseObject(payload))); + }; + const handleSkip = e => { + e.preventDefault(); + setSkipButtonState(PENDING_STATE); + const hasCountry = !!countryCookieValue || !!authContextCountryCode; + if (hasFormErrors() && !hasCountry) { + setFormErrors(_objectSpread(_objectSpread({}, formErrors), {}, { + country: formatMessage(messages.progressiveProfilingCountryFieldErrorMessage) + })); + setSkipButtonState(FAILURE_STATE); + moveScrollToTop(countryFieldRef); + } else if (!hasFormErrors() && !hasCountry) { + setFormErrors(_objectSpread(_objectSpread({}, formErrors), {}, { + country: formatMessage(messages.progressiveProfilingCountryFieldBlockingErrorMessage) + })); + setSkipButtonState(FAILURE_STATE); + moveScrollToTop(countryFieldRef); + } else if (hasCountry) { + // link tracker + trackProgressiveProfilingSkipLinkClick(redirectUrl)(e); + } + }; + return /*#__PURE__*/React.createElement(Container, { + size: "lg", + className: "authn__popup-progressive-profiling-container m-0 overflow-auto" + }, /*#__PURE__*/React.createElement(AuthenticatedRedirection, { + success: submitState === COMPLETE_STATE, + redirectUrl: redirectUrl, + finishAuthUrl: finishAuthUrl, + isLinkTracked: true + }), /*#__PURE__*/React.createElement("h1", { + className: "display-1 font-italic text-center mb-4", + "data-testid": "progressive-profiling-heading" + }, formatMessage(messages.progressiveProfilingFormHeading)), /*#__PURE__*/React.createElement("p", { + className: "text-center" + }, formatMessage(messages.progressiveProfilingCompletionSkipMessage)), /*#__PURE__*/React.createElement("hr", { + className: "heading-separator mb-3 mt-3" + }), /*#__PURE__*/React.createElement(Form, { + id: "progressive-profiling", + name: "progressive-profiling" + }, /*#__PURE__*/React.createElement("h3", { + className: "mb-2.5 mt-2" + }, formatMessage(messages.progressiveProfilingCountryFieldTitle)), /*#__PURE__*/React.createElement("p", { + className: "x-small", + ref: countryFieldRef + }, formatMessage(messages.progressiveProfilingCountryFieldInfoMessage)), /*#__PURE__*/React.createElement(Form.Group, { + controlId: "country", + className: "mb-4.5" + }, /*#__PURE__*/React.createElement(AutoSuggestField, { + name: "country", + leadingElement: /*#__PURE__*/React.createElement(Icon, { + src: Language + }), + feedBack: formatMessage(messages.progressiveProfilingCountryFieldHelpText), + placeholder: formatMessage(messages.useProfileCountryFieldUndetected), + options: countryList, + selectedOption: autoFilledCountry, + errorMessage: formErrors?.country, + onChangeHandler: handleSelect, + onFocusHandler: onFieldFocus, + onBlurHandler: onFieldBlur + })), /*#__PURE__*/React.createElement("h3", { + className: "mb-2.5" + }, formatMessage(messages.progressiveProfilingDataCollectionTitle)), /*#__PURE__*/React.createElement(Form.Group, { + controlId: "subject", + className: "mb-4" + }, /*#__PURE__*/React.createElement(AutoSuggestField, { + name: "subject", + placeholder: formatMessage(messages.progressiveProfilingSubjectFieldPlaceholder), + label: formatMessage(messages.progressiveProfilingSubjectFieldLabel), + options: subjectsList?.options, + onChangeHandler: handleSelect + })), /*#__PURE__*/React.createElement(Form.Group, { + controlId: "levelOfEducation", + className: "mb-4" + }, /*#__PURE__*/React.createElement(AutoSuggestField, { + name: "levelOfEducation", + placeholder: formatMessage(messages.progressiveProfilingLevelOfEducationFieldPlaceholder), + label: formatMessage(messages.progressiveProfilingLevelOfEducationFieldLabel), + options: optionalFieldsData.levelOfEducation.options, + onChangeHandler: handleSelect + })), /*#__PURE__*/React.createElement(Form.Group, { + controlId: "workExperience", + className: "mb-4" + }, /*#__PURE__*/React.createElement(AutoSuggestField, { + name: "workExperience", + placeholder: formatMessage(messages.progressiveProfilingWorkExperienceFieldPlaceholder), + label: formatMessage(messages.progressiveProfilingWorkExperienceFieldLabel), + options: optionalFieldsData.workExperience.options, + onChangeHandler: handleSelect + })), /*#__PURE__*/React.createElement(Form.Group, { + controlId: "learningType", + className: "mb-4" + }, /*#__PURE__*/React.createElement(AutoSuggestField, { + name: "learningType", + placeholder: formatMessage(messages.progressiveProfilingLearningTypeFieldPlaceholder), + label: formatMessage(messages.progressiveProfilingLearningTypeFieldLabel), + options: optionalFieldsData.learningType.options, + onChangeHandler: handleSelect + })), /*#__PURE__*/React.createElement(Form.Group, { + controlId: "gender", + className: "mb-4" + }, /*#__PURE__*/React.createElement(Form.Label, null, formatMessage(messages.progressiveProfilingGenderFieldLabel)), /*#__PURE__*/React.createElement(Form.RadioSet, { + value: formData.gender, + name: "gender", + onChange: radioButtonOnChangeHandler, + isInline: true + }, optionalFieldsData.gender.options.map(option => /*#__PURE__*/React.createElement(Form.Radio, { + value: option.label, + key: option.label + }, formatMessage(messages[`gender.option.${option.label}`]))))), /*#__PURE__*/React.createElement("div", { + className: "d-flex my-4 justify-content-end progressive-profiling__cta-btn-container" + }, /*#__PURE__*/React.createElement(StatefulButton, { + id: "skip-optional-fields", + name: "skip-optional-fields", + className: "authn-progressive-profiling-skip-button authn-btn__pill-shaped", + type: "submit", + variant: "outline-dark", + state: skipButtonState, + labels: { + default: formatMessage(messages.progressiveProfilingSkipForNowButtonText), + pending: '' + }, + onClick: handleSkip, + onMouseDown: e => e.preventDefault() + }), /*#__PURE__*/React.createElement(StatefulButton, { + id: "submit-optional-fields", + name: "submit-optional-fields", + className: "authn-progressive-profiling-submit-button authn-btn__pill-shaped", + type: "submit", + state: submitState, + labels: { + default: formatMessage(messages.progressiveProfilingSubmitButtonText), + pending: '' + }, + onClick: handleSubmit, + onMouseDown: e => e.preventDefault() + })))); +}; +export default ProgressiveProfilingForm; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/forms/progressive-profiling-popup/index.js.map b/dist/forms/progressive-profiling-popup/index.js.map new file mode 100644 index 00000000..0535d125 --- /dev/null +++ b/dist/forms/progressive-profiling-popup/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["React","useEffect","useMemo","useRef","useState","getConfig","snakeCaseObject","identifyAuthenticatedUser","AxiosJwtAuthService","configure","configureAuth","getCountryList","getLocale","useIntl","getLoggingService","Container","Form","Icon","StatefulButton","Language","extendedProfileFields","optionalFieldsData","saveUserProfile","messages","setCurrentOpenedForm","COMPLETE_STATE","DEFAULT_STATE","FAILURE_STATE","LOGIN_FORM","PENDING_STATE","useDispatch","useSelector","getCountryCookieValue","moveScrollToTop","trackProgressiveProfilingPageViewed","trackProgressiveProfilingSkipLinkClick","trackProgressiveProfilingSubmitClick","AuthenticatedRedirection","AutoSuggestField","ProgressiveProfilingForm","formatMessage","dispatch","countryFieldRef","countryCookieValue","countryList","submitState","state","progressiveProfiling","subjectsList","redirectUrl","authContextCountryCode","commonData","thirdPartyAuthContext","countryCode","finishAuthUrl","authenticatedUser","register","registrationResult","formData","setFormData","formErrors","setFormErrors","autoFilledCountry","setAutoFilledCountry","value","displayText","skipButtonState","setSkipButtonState","userCountry","find","country","code","name","userId","loggingService","config","hasFormErrors","error","_objectSpread","progressiveProfilingCountryFieldErrorMessage","handleSelect","e","text","target","radioButtonOnChangeHandler","onFieldFocus","onFieldBlur","handleSubmit","preventDefault","eventProperties","isGenderSelected","gender","isLevelOfEducationSelected","levelOfEducation","isWorkExperienceSelected","workExperience","isSubjectSelected","subject","isLearningTypeSelected","learningType","extendedProfile","Object","keys","length","forEach","fieldName","includes","push","fieldValue","payload","username","data","handleSkip","hasCountry","progressiveProfilingCountryFieldBlockingErrorMessage","createElement","size","className","success","isLinkTracked","progressiveProfilingFormHeading","progressiveProfilingCompletionSkipMessage","id","progressiveProfilingCountryFieldTitle","ref","progressiveProfilingCountryFieldInfoMessage","Group","controlId","leadingElement","src","feedBack","progressiveProfilingCountryFieldHelpText","placeholder","useProfileCountryFieldUndetected","options","selectedOption","errorMessage","onChangeHandler","onFocusHandler","onBlurHandler","progressiveProfilingDataCollectionTitle","progressiveProfilingSubjectFieldPlaceholder","label","progressiveProfilingSubjectFieldLabel","progressiveProfilingLevelOfEducationFieldPlaceholder","progressiveProfilingLevelOfEducationFieldLabel","progressiveProfilingWorkExperienceFieldPlaceholder","progressiveProfilingWorkExperienceFieldLabel","progressiveProfilingLearningTypeFieldPlaceholder","progressiveProfilingLearningTypeFieldLabel","Label","progressiveProfilingGenderFieldLabel","RadioSet","onChange","isInline","map","option","Radio","key","type","variant","labels","default","progressiveProfilingSkipForNowButtonText","pending","onClick","onMouseDown","progressiveProfilingSubmitButtonText"],"sources":["../../../src/forms/progressive-profiling-popup/index.jsx"],"sourcesContent":["import React, {\n useEffect, useMemo, useRef, useState,\n} from 'react';\n\nimport { getConfig, snakeCaseObject } from '@edx/frontend-platform';\nimport { identifyAuthenticatedUser } from '@edx/frontend-platform/analytics';\nimport {\n AxiosJwtAuthService,\n configure as configureAuth,\n} from '@edx/frontend-platform/auth';\nimport { getCountryList, getLocale, useIntl } from '@edx/frontend-platform/i18n';\nimport { getLoggingService } from '@edx/frontend-platform/logging';\nimport {\n Container, Form, Icon, StatefulButton,\n} from '@openedx/paragon';\nimport { Language } from '@openedx/paragon/icons';\n\nimport { extendedProfileFields, optionalFieldsData } from './data/constants';\nimport { saveUserProfile } from './data/reducers';\nimport messages from './messages';\nimport { setCurrentOpenedForm } from '../../authn-component/data/reducers';\nimport {\n COMPLETE_STATE,\n DEFAULT_STATE,\n FAILURE_STATE,\n LOGIN_FORM,\n PENDING_STATE,\n} from '../../data/constants';\nimport { useDispatch, useSelector } from '../../data/storeHooks';\nimport { getCountryCookieValue, moveScrollToTop } from '../../data/utils';\nimport {\n trackProgressiveProfilingPageViewed,\n trackProgressiveProfilingSkipLinkClick,\n trackProgressiveProfilingSubmitClick,\n} from '../../tracking/trackers/progressive-profiling';\nimport AuthenticatedRedirection from '../common-components/AuthenticatedRedirection';\nimport AutoSuggestField from '../fields/auto-suggested-field';\n\nimport './index.scss';\n\n/**\n * Progressive profiling form component. This component holds the logic to render optional demographic\n * form fields and infor users about the auto-generated country field.\n *\n * @returns {JSX.Element} Progressive profiling form rendered inside BaseContainer component.\n */\nconst ProgressiveProfilingForm = () => {\n const { formatMessage } = useIntl();\n const dispatch = useDispatch();\n\n const countryFieldRef = useRef(null);\n\n const countryCookieValue = getCountryCookieValue();\n const countryList = useMemo(() => getCountryList(getLocale()), []);\n\n const submitState = useSelector(state => state.progressiveProfiling.submitState);\n const subjectsList = useSelector(state => state.progressiveProfiling.subjectsList);\n const redirectUrl = useSelector(state => state.progressiveProfiling.redirectUrl);\n const authContextCountryCode = useSelector(state => state.commonData.thirdPartyAuthContext.countryCode);\n const finishAuthUrl = useSelector(state => state.commonData.thirdPartyAuthContext.finishAuthUrl);\n const authenticatedUser = useSelector(state => state.register.registrationResult.authenticatedUser);\n\n const [formData, setFormData] = useState({});\n const [formErrors, setFormErrors] = useState({});\n const [autoFilledCountry, setAutoFilledCountry] = useState({ value: '', displayText: '' });\n const [skipButtonState, setSkipButtonState] = useState(DEFAULT_STATE);\n\n useEffect(() => {\n let countryCode = null;\n if (countryCookieValue) {\n countryCode = countryCookieValue;\n } else if (authContextCountryCode) {\n countryCode = authContextCountryCode;\n }\n\n if (!countryCode) {\n return;\n }\n const userCountry = countryList.find((country) => country.code === countryCode);\n if (userCountry?.code !== '' && autoFilledCountry.value === '') {\n setAutoFilledCountry({ value: userCountry?.code, displayText: userCountry?.name });\n // set formData state for auto populated country field to pass into payload\n setFormData({ country: userCountry?.code });\n }\n }, [authContextCountryCode, autoFilledCountry, countryCookieValue, countryList, formatMessage]);\n\n useEffect(() => {\n if (authenticatedUser === null) {\n dispatch(setCurrentOpenedForm(LOGIN_FORM));\n }\n if (authenticatedUser?.userId) {\n identifyAuthenticatedUser(authenticatedUser?.userId);\n configureAuth(AxiosJwtAuthService, { loggingService: getLoggingService(), config: getConfig() });\n trackProgressiveProfilingPageViewed();\n }\n }, [authenticatedUser, dispatch]);\n\n const hasFormErrors = () => {\n let error = false;\n if (!('country' in formData) || (formData?.country === '')) {\n setFormErrors({ ...formErrors, country: formatMessage(messages.progressiveProfilingCountryFieldErrorMessage) });\n error = true;\n }\n return error;\n };\n\n const handleSelect = (e) => {\n const { name, value, text } = e.target;\n\n if (text === '') {\n setFormErrors({ ...formErrors, [name]: formatMessage(messages.progressiveProfilingCountryFieldErrorMessage) });\n } else if (value) {\n setFormErrors({ ...formErrors, [name]: '' });\n }\n setFormData({ ...formData, [name]: value });\n };\n\n const radioButtonOnChangeHandler = (e) => {\n const { name, value } = e.target;\n setFormData({ ...formData, [name]: value });\n };\n\n const onFieldFocus = (e) => {\n const { name, value } = e.target;\n setFormErrors({ ...formErrors, [name]: value });\n };\n\n const onFieldBlur = (e) => {\n const { name, value } = e.target;\n\n if (value === '') {\n setFormErrors({ ...formErrors, [name]: formatMessage(messages.progressiveProfilingCountryFieldErrorMessage) });\n }\n };\n\n const handleSubmit = (e) => {\n e.preventDefault();\n\n if (hasFormErrors()) {\n moveScrollToTop(countryFieldRef);\n return;\n }\n const eventProperties = {\n isGenderSelected: !!formData.gender,\n isLevelOfEducationSelected: !!formData.levelOfEducation,\n isWorkExperienceSelected: !!formData.workExperience,\n isSubjectSelected: !!formData.subject,\n isLearningTypeSelected: !!formData.learningType,\n };\n\n const extendedProfile = [];\n if (Object.keys(formData).length > 0) {\n Object.keys(formData).forEach(fieldName => {\n if (extendedProfileFields.includes(fieldName)) {\n extendedProfile.push({ fieldName, fieldValue: formData[fieldName] });\n delete formData[fieldName];\n }\n });\n }\n const payload = {\n username: authenticatedUser?.username,\n data: {\n extendedProfile,\n ...formData,\n },\n };\n trackProgressiveProfilingSubmitClick(eventProperties);\n dispatch(saveUserProfile(snakeCaseObject(payload)));\n };\n\n const handleSkip = (e) => {\n e.preventDefault();\n\n setSkipButtonState(PENDING_STATE);\n const hasCountry = !!countryCookieValue || !!authContextCountryCode;\n\n if (hasFormErrors() && !hasCountry) {\n setFormErrors({ ...formErrors, country: formatMessage(messages.progressiveProfilingCountryFieldErrorMessage) });\n setSkipButtonState(FAILURE_STATE);\n moveScrollToTop(countryFieldRef);\n } else if (!hasFormErrors() && !hasCountry) {\n setFormErrors({\n ...formErrors,\n country: formatMessage(messages.progressiveProfilingCountryFieldBlockingErrorMessage),\n });\n setSkipButtonState(FAILURE_STATE);\n moveScrollToTop(countryFieldRef);\n } else if (hasCountry) {\n // link tracker\n trackProgressiveProfilingSkipLinkClick(redirectUrl)(e);\n }\n };\n\n return (\n \n \n \n {formatMessage(messages.progressiveProfilingFormHeading)}\n \n

\n {formatMessage(messages.progressiveProfilingCompletionSkipMessage)}\n

\n
\n
\n

\n {formatMessage(messages.progressiveProfilingCountryFieldTitle)}\n

\n \n {formatMessage(messages.progressiveProfilingCountryFieldInfoMessage)}\n

\n \n }\n feedBack={formatMessage(messages.progressiveProfilingCountryFieldHelpText)}\n placeholder={formatMessage(messages.useProfileCountryFieldUndetected)}\n options={countryList}\n selectedOption={autoFilledCountry}\n errorMessage={formErrors?.country}\n onChangeHandler={handleSelect}\n onFocusHandler={onFieldFocus}\n onBlurHandler={onFieldBlur}\n />\n \n

\n {formatMessage(messages.progressiveProfilingDataCollectionTitle)}\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n {formatMessage(messages.progressiveProfilingGenderFieldLabel)}\n \n \n {optionalFieldsData.gender.options.map(option => (\n \n {formatMessage(messages[`gender.option.${option.label}`])}\n \n ))}\n \n \n
\n e.preventDefault()}\n />\n e.preventDefault()}\n />\n
\n \n
\n );\n};\n\nexport default ProgressiveProfilingForm;\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/progressive-profiling-popup/index.scss b/dist/forms/progressive-profiling-popup/index.scss new file mode 100644 index 00000000..48c97888 --- /dev/null +++ b/dist/forms/progressive-profiling-popup/index.scss @@ -0,0 +1,21 @@ +.progressive-profiling__cta-btn-container { + gap: 12px !important; +} + +.authn__popup-progressive-profiling-container { + padding: 4rem 7.5rem !important; + @media (max-width: 767px) { + padding: 2.5rem 1.5rem !important; + } + @media (max-width: 576px) { + padding: 2.5rem 1rem !important; + } +} + +.authn-progressive-profiling-submit-button { + min-width: 5.938rem !important; +} + +.authn-progressive-profiling-skip-button { + min-width: 8.68rem !important; +} diff --git a/dist/forms/progressive-profiling-popup/messages.js b/dist/forms/progressive-profiling-popup/messages.js new file mode 100644 index 00000000..d32c1dd7 --- /dev/null +++ b/dist/forms/progressive-profiling-popup/messages.js @@ -0,0 +1,386 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; +const messages = defineMessages({ + progressiveProfilingFormHeading: { + id: 'progressive.profiling.form.heading', + defaultMessage: 'Fill out your profile', + description: 'Heading for the form that appears after a user registers with edX' + }, + progressiveProfilingCompletionSkipMessage: { + id: 'progressive.profiling.completion.skip.message', + defaultMessage: 'If you skip now, you can complete your profile under "Account settings" at any time.', + description: 'Message that appears on the user profile completion form' + }, + progressiveProfilingCountryFieldTitle: { + id: 'progressive.profiling.country.field.title', + defaultMessage: 'Confirm your country of residence', + description: 'Title for the country field' + }, + progressiveProfilingCountryFieldInfoMessage: { + id: 'progressive.profiling.country.field.info.message', + defaultMessage: 'We have determined your country of residence. If this is incorrect, please edit your country.', + description: 'Informative message for the auto-populated country field' + }, + useProfileCountryFieldUndetected: { + id: 'progressive.profiling.country.field.undetected', + defaultMessage: 'Undetected', + description: 'Placeholder text for country field when we are not able to auto-detect the country' + }, + progressiveProfilingCountryFieldHelpText: { + id: 'progressive.profiling.country.field.help.text', + defaultMessage: 'Your country of residence determines availability of certain courses', + description: 'Help text for country field' + }, + progressiveProfilingCountryFieldErrorMessage: { + id: 'progressive.profiling.country.field.error.message', + defaultMessage: 'Select a valid option', + description: 'Error text appers on the country field when country is not selected and the user submit the form' + }, + // TODO update error message copy here when design team will provide it + progressiveProfilingCountryFieldBlockingErrorMessage: { + id: 'progressive.profiling.country.field.error.message', + defaultMessage: 'To proceed, please save your country of residence', + description: 'Error msg for country field when the user country is not detected on registration step and user want to skip progressive profiling form' + }, + progressiveProfilingDataCollectionTitle: { + id: 'progressive.profiling.data.collection.title', + defaultMessage: 'Personalize your experience', + description: 'Title that appears above optional demographic fields' + }, + progressiveProfilingSubjectFieldLabel: { + id: 'progressive.profiling.subject.field.label', + defaultMessage: 'What field are you interested in?', + description: '"Subject" field label' + }, + progressiveProfilingSubjectFieldPlaceholder: { + id: 'progressive.profiling.subject.field.placeholder', + defaultMessage: 'Select a field', + description: '"Subject" field placeholder text' + }, + progressiveProfilingLevelOfEducationFieldLabel: { + id: 'progressive.profiling.level.of.education.field.label', + defaultMessage: 'What is the highest level of education you have completed?', + description: '"Level of Education" field label' + }, + progressiveProfilingLevelOfEducationFieldPlaceholder: { + id: 'progressive.profiling.level.of.education.field.placeholder', + defaultMessage: 'Select a level', + description: '"Level of Education" field placeholder text' + }, + progressiveProfilingWorkExperienceFieldLabel: { + id: 'progressive.profiling.work.experience.field.label', + defaultMessage: 'How many years of work experience do you have?', + description: '"Work Experience" field label' + }, + progressiveProfilingWorkExperienceFieldPlaceholder: { + id: 'progressive.profiling.work.experience.field.placeholder', + defaultMessage: 'Select an option', + description: '"Work Experience" field placeholder text' + }, + progressiveProfilingLearningTypeFieldLabel: { + id: 'progressive.profiling.learning.type.field.label', + defaultMessage: 'What type of experience are you interested in?', + description: '"Learning Type" field label' + }, + progressiveProfilingLearningTypeFieldPlaceholder: { + id: 'progressive.profiling.learning.type.field.placeholder', + defaultMessage: 'Select a product', + description: '"Learning Type" field placeholder text' + }, + progressiveProfilingGenderFieldLabel: { + id: 'progressive.profiling.gender.field.label', + defaultMessage: 'What is your gender?', + description: '"Gender" field label' + }, + progressiveProfilingGenderFieldPlaceholder: { + id: 'progressive.profiling.gender.field.placeholder', + defaultMessage: 'Select an option', + description: '"Gender" field placeholder text' + }, + progressiveProfilingSkipForNowButtonText: { + id: 'progressive.profiling.skip.for.now.button.text', + defaultMessage: 'Skip for now', + description: 'Text that appears on the button that skips the optional profile data form' + }, + progressiveProfilingSubmitButtonText: { + id: 'progressive.profiling.submit.button.text', + defaultMessage: 'Submit', + description: 'Text that appears on the button that submits the optional profile data form' + }, + // Subject Options + 'subject.option.Business & Management': { + id: 'subject.option.Business & Management', + defaultMessage: 'Business & Management', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Computer Science': { + id: 'subject.option.Computer Science', + defaultMessage: 'Computer Science', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Engineering': { + id: 'subject.option.Engineering', + defaultMessage: 'Engineering', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Social Sciences': { + id: 'subject.option.Social Sciences', + defaultMessage: 'Social Sciences', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Data Analysis & Statistics': { + id: 'subject.option.Data Analysis & Statistics', + defaultMessage: 'Data Analysis & Statistics', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Economics & Finance': { + id: 'subject.option.Economics & Finance', + defaultMessage: 'Economics & Finance', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Communication': { + id: 'subject.option.Communication', + defaultMessage: 'Communication', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Humanities': { + id: 'subject.option.Humanities', + defaultMessage: 'Humanities', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Science': { + id: 'subject.option.Science', + defaultMessage: 'Science', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Environmental Studies': { + id: 'subject.option.Environmental Studies', + defaultMessage: 'Environmental Studies', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Medicine': { + id: 'subject.option.Medicine', + defaultMessage: 'Medicine', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Biology & Life Sciences': { + id: 'subject.option.Biology & Life Sciences', + defaultMessage: 'Biology & Life Sciences', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Health & Safety': { + id: 'subject.option.Health & Safety', + defaultMessage: 'Health & Safety', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Education & Teacher Training': { + id: 'subject.option.Education & Teacher Training', + defaultMessage: 'Education & Teacher Training', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Art & Culture': { + id: 'subject.option.Art & Culture', + defaultMessage: 'Art & Culture', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Math': { + id: 'subject.option.Math', + defaultMessage: 'Math', + description: 'Option for the subject dropdown field' + }, + 'subject.option.History': { + id: 'subject.option.History', + defaultMessage: 'History', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Design': { + id: 'subject.option.Design', + defaultMessage: 'Design', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Physics': { + id: 'subject.option.Physics', + defaultMessage: 'Physics', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Energy & Earth Sciences': { + id: 'subject.option.Energy & Earth Sciences', + defaultMessage: 'Energy & Earth Sciences', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Law': { + id: 'subject.option.Law', + defaultMessage: 'Law', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Philosophy & Ethics': { + id: 'subject.option.Philosophy & Ethics', + defaultMessage: 'Philosophy & Ethics', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Language': { + id: 'subject.option.Language', + defaultMessage: 'Language', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Electronics': { + id: 'subject.option.Electronics', + defaultMessage: 'Electronics', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Food & Nutrition': { + id: 'subject.option.Food & Nutrition', + defaultMessage: 'Food & Nutrition', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Architecture': { + id: 'subject.option.Architecture', + defaultMessage: 'Architecture', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Chemistry': { + id: 'subject.option.Chemistry', + defaultMessage: 'Chemistry', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Literature': { + id: 'subject.option.Literature', + defaultMessage: 'Literature', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Ethics': { + id: 'subject.option.Ethics', + defaultMessage: 'Ethics', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Music': { + id: 'subject.option.Music', + defaultMessage: 'Music', + description: 'Option for the subject dropdown field' + }, + 'subject.option.Philanthropy': { + id: 'subject.option.Philanthropy', + defaultMessage: 'Philanthropy', + description: 'Option for the subject dropdown field' + }, + // Level of Education Options + 'levelOfEducation.option.none': { + id: 'levelOfEducation.option.none', + defaultMessage: 'No formal education', + description: 'Option for education level field' + }, + 'levelOfEducation.option.jhs': { + id: 'levelOfEducation.option.jhs', + defaultMessage: 'Junior secondary/junior high/middle school', + description: 'Option for education level field' + }, + 'levelOfEducation.option.hs': { + id: 'levelOfEducation.option.hs', + defaultMessage: 'Secondary/High School', + description: 'Option for education level field' + }, + 'levelOfEducation.option.a': { + id: 'levelOfEducation.option.a', + defaultMessage: 'Associate Degree', + description: 'Option for education level field' + }, + 'levelOfEducation.option.b': { + id: 'levelOfEducation.option.b', + defaultMessage: 'Bachelor\'s Degree', + description: 'Option for education level field' + }, + 'levelOfEducation.option.m': { + id: 'levelOfEducation.option.m', + defaultMessage: 'Master\'s or professional degree', + description: 'Option for education level field' + }, + 'levelOfEducation.option.p': { + id: 'levelOfEducation.option.p', + defaultMessage: 'Doctorate', + description: 'Option for education level field' + }, + 'levelOfEducation.option.other': { + id: 'levelOfEducation.option.other', + defaultMessage: 'Other', + description: 'Option for education level field' + }, + // Work Experience Options + 'workExperience.option.0yrs': { + id: 'workExperience.option.0yrs', + defaultMessage: 'I don’t have any work experience', + description: 'Option for work experience field' + }, + 'workExperience.option.1-5yrs': { + id: 'workExperience.option.1-5yrs', + defaultMessage: 'I have 1-5 years of work experience', + description: 'Option for work experience field' + }, + 'workExperience.option.6-10yrs': { + id: 'workExperience.option.6-10yrs', + defaultMessage: 'I have 6-10 years of work experience', + description: 'Option for work experience field' + }, + 'workExperience.option.11-15yrs': { + id: 'workExperience.option.11-15yrs', + defaultMessage: 'I have 11-15 years of work experience', + description: 'Option for work experience field' + }, + 'workExperience.option.16-20yrs': { + id: 'workExperience.option.16-20yrs', + defaultMessage: 'I have 16-20 years of work experience', + description: 'Option for work experience field' + }, + 'workExperience.option.20+yrs': { + id: 'workExperience.option.20+yrs', + defaultMessage: 'More than 20 years of work experience', + description: 'Option for work experience field' + }, + // Learning Experience Options + 'learningType.option.Courses': { + id: 'learningType.option.Courses', + defaultMessage: 'Courses', + description: 'Option for learning type dropdown field' + }, + 'learningType.option.Programs': { + id: 'learningType.option.Programs', + defaultMessage: 'Programs', + description: 'Option for learning type dropdown field' + }, + 'learningType.option.Boot Camps': { + id: 'learningType.option.Boot Camps', + defaultMessage: 'Boot Camps', + description: 'Option for learning type dropdown field' + }, + 'learningType.option.Degrees': { + id: 'learningType.option.Degree Programs', + defaultMessage: 'Degrees', + description: 'Option for learning type dropdown field' + }, + 'learningType.option.Executive Education': { + id: 'learningType.option.Executive Education', + defaultMessage: 'Executive Education', + description: 'Option for learning type dropdown field' + }, + 'learningType.option.unsure': { + id: 'learningType.option.Unsure', + defaultMessage: 'Unsure', + description: 'Option for learning type dropdown field' + }, + // Gender Options + 'gender.option.m': { + id: 'gender.option.m', + defaultMessage: 'Male', + description: 'Option for gender field' + }, + 'gender.option.f': { + id: 'gender.option.f', + defaultMessage: 'Female', + description: 'Option for gender field' + }, + 'gender.option.o': { + id: 'gender.option.o', + defaultMessage: 'Other/prefer not to answer', + description: 'Option for gender field' + } +}); +export default messages; +//# sourceMappingURL=messages.js.map \ No newline at end of file diff --git a/dist/forms/progressive-profiling-popup/messages.js.map b/dist/forms/progressive-profiling-popup/messages.js.map new file mode 100644 index 00000000..f9fd8f2c --- /dev/null +++ b/dist/forms/progressive-profiling-popup/messages.js.map @@ -0,0 +1 @@ +{"version":3,"file":"messages.js","names":["defineMessages","messages","progressiveProfilingFormHeading","id","defaultMessage","description","progressiveProfilingCompletionSkipMessage","progressiveProfilingCountryFieldTitle","progressiveProfilingCountryFieldInfoMessage","useProfileCountryFieldUndetected","progressiveProfilingCountryFieldHelpText","progressiveProfilingCountryFieldErrorMessage","progressiveProfilingCountryFieldBlockingErrorMessage","progressiveProfilingDataCollectionTitle","progressiveProfilingSubjectFieldLabel","progressiveProfilingSubjectFieldPlaceholder","progressiveProfilingLevelOfEducationFieldLabel","progressiveProfilingLevelOfEducationFieldPlaceholder","progressiveProfilingWorkExperienceFieldLabel","progressiveProfilingWorkExperienceFieldPlaceholder","progressiveProfilingLearningTypeFieldLabel","progressiveProfilingLearningTypeFieldPlaceholder","progressiveProfilingGenderFieldLabel","progressiveProfilingGenderFieldPlaceholder","progressiveProfilingSkipForNowButtonText","progressiveProfilingSubmitButtonText"],"sources":["../../../src/forms/progressive-profiling-popup/messages.js"],"sourcesContent":["import { defineMessages } from '@edx/frontend-platform/i18n';\n\nconst messages = defineMessages({\n progressiveProfilingFormHeading: {\n id: 'progressive.profiling.form.heading',\n defaultMessage: 'Fill out your profile',\n description: 'Heading for the form that appears after a user registers with edX',\n },\n progressiveProfilingCompletionSkipMessage: {\n id: 'progressive.profiling.completion.skip.message',\n defaultMessage: 'If you skip now, you can complete your profile under \"Account settings\" at any time.',\n description: 'Message that appears on the user profile completion form',\n },\n progressiveProfilingCountryFieldTitle: {\n id: 'progressive.profiling.country.field.title',\n defaultMessage: 'Confirm your country of residence',\n description: 'Title for the country field',\n },\n progressiveProfilingCountryFieldInfoMessage: {\n id: 'progressive.profiling.country.field.info.message',\n defaultMessage: 'We have determined your country of residence. If this is incorrect, please edit your country.',\n description: 'Informative message for the auto-populated country field',\n },\n useProfileCountryFieldUndetected: {\n id: 'progressive.profiling.country.field.undetected',\n defaultMessage: 'Undetected',\n description: 'Placeholder text for country field when we are not able to auto-detect the country',\n },\n progressiveProfilingCountryFieldHelpText: {\n id: 'progressive.profiling.country.field.help.text',\n defaultMessage: 'Your country of residence determines availability of certain courses',\n description: 'Help text for country field',\n },\n progressiveProfilingCountryFieldErrorMessage: {\n id: 'progressive.profiling.country.field.error.message',\n defaultMessage: 'Select a valid option',\n description: 'Error text appers on the country field when country is not selected and the user submit the form',\n },\n // TODO update error message copy here when design team will provide it\n progressiveProfilingCountryFieldBlockingErrorMessage: {\n id: 'progressive.profiling.country.field.error.message',\n defaultMessage: 'To proceed, please save your country of residence',\n description: 'Error msg for country field when the user country is not detected on registration step and user want to skip progressive profiling form',\n },\n progressiveProfilingDataCollectionTitle: {\n id: 'progressive.profiling.data.collection.title',\n defaultMessage: 'Personalize your experience',\n description: 'Title that appears above optional demographic fields',\n },\n progressiveProfilingSubjectFieldLabel: {\n id: 'progressive.profiling.subject.field.label',\n defaultMessage: 'What field are you interested in?',\n description: '\"Subject\" field label',\n },\n progressiveProfilingSubjectFieldPlaceholder: {\n id: 'progressive.profiling.subject.field.placeholder',\n defaultMessage: 'Select a field',\n description: '\"Subject\" field placeholder text',\n },\n progressiveProfilingLevelOfEducationFieldLabel: {\n id: 'progressive.profiling.level.of.education.field.label',\n defaultMessage: 'What is the highest level of education you have completed?',\n description: '\"Level of Education\" field label',\n },\n progressiveProfilingLevelOfEducationFieldPlaceholder: {\n id: 'progressive.profiling.level.of.education.field.placeholder',\n defaultMessage: 'Select a level',\n description: '\"Level of Education\" field placeholder text',\n },\n progressiveProfilingWorkExperienceFieldLabel: {\n id: 'progressive.profiling.work.experience.field.label',\n defaultMessage: 'How many years of work experience do you have?',\n description: '\"Work Experience\" field label',\n },\n progressiveProfilingWorkExperienceFieldPlaceholder: {\n id: 'progressive.profiling.work.experience.field.placeholder',\n defaultMessage: 'Select an option',\n description: '\"Work Experience\" field placeholder text',\n },\n progressiveProfilingLearningTypeFieldLabel: {\n id: 'progressive.profiling.learning.type.field.label',\n defaultMessage: 'What type of experience are you interested in?',\n description: '\"Learning Type\" field label',\n },\n progressiveProfilingLearningTypeFieldPlaceholder: {\n id: 'progressive.profiling.learning.type.field.placeholder',\n defaultMessage: 'Select a product',\n description: '\"Learning Type\" field placeholder text',\n },\n progressiveProfilingGenderFieldLabel: {\n id: 'progressive.profiling.gender.field.label',\n defaultMessage: 'What is your gender?',\n description: '\"Gender\" field label',\n },\n progressiveProfilingGenderFieldPlaceholder: {\n id: 'progressive.profiling.gender.field.placeholder',\n defaultMessage: 'Select an option',\n description: '\"Gender\" field placeholder text',\n },\n progressiveProfilingSkipForNowButtonText: {\n id: 'progressive.profiling.skip.for.now.button.text',\n defaultMessage: 'Skip for now',\n description: 'Text that appears on the button that skips the optional profile data form',\n },\n progressiveProfilingSubmitButtonText: {\n id: 'progressive.profiling.submit.button.text',\n defaultMessage: 'Submit',\n description: 'Text that appears on the button that submits the optional profile data form',\n },\n // Subject Options\n 'subject.option.Business & Management': {\n id: 'subject.option.Business & Management',\n defaultMessage: 'Business & Management',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Computer Science': {\n id: 'subject.option.Computer Science',\n defaultMessage: 'Computer Science',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Engineering': {\n id: 'subject.option.Engineering',\n defaultMessage: 'Engineering',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Social Sciences': {\n id: 'subject.option.Social Sciences',\n defaultMessage: 'Social Sciences',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Data Analysis & Statistics': {\n id: 'subject.option.Data Analysis & Statistics',\n defaultMessage: 'Data Analysis & Statistics',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Economics & Finance': {\n id: 'subject.option.Economics & Finance',\n defaultMessage: 'Economics & Finance',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Communication': {\n id: 'subject.option.Communication',\n defaultMessage: 'Communication',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Humanities': {\n id: 'subject.option.Humanities',\n defaultMessage: 'Humanities',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Science': {\n id: 'subject.option.Science',\n defaultMessage: 'Science',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Environmental Studies': {\n id: 'subject.option.Environmental Studies',\n defaultMessage: 'Environmental Studies',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Medicine': {\n id: 'subject.option.Medicine',\n defaultMessage: 'Medicine',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Biology & Life Sciences': {\n id: 'subject.option.Biology & Life Sciences',\n defaultMessage: 'Biology & Life Sciences',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Health & Safety': {\n id: 'subject.option.Health & Safety',\n defaultMessage: 'Health & Safety',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Education & Teacher Training': {\n id: 'subject.option.Education & Teacher Training',\n defaultMessage: 'Education & Teacher Training',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Art & Culture': {\n id: 'subject.option.Art & Culture',\n defaultMessage: 'Art & Culture',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Math': {\n id: 'subject.option.Math',\n defaultMessage: 'Math',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.History': {\n id: 'subject.option.History',\n defaultMessage: 'History',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Design': {\n id: 'subject.option.Design',\n defaultMessage: 'Design',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Physics': {\n id: 'subject.option.Physics',\n defaultMessage: 'Physics',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Energy & Earth Sciences': {\n id: 'subject.option.Energy & Earth Sciences',\n defaultMessage: 'Energy & Earth Sciences',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Law': {\n id: 'subject.option.Law',\n defaultMessage: 'Law',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Philosophy & Ethics': {\n id: 'subject.option.Philosophy & Ethics',\n defaultMessage: 'Philosophy & Ethics',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Language': {\n id: 'subject.option.Language',\n defaultMessage: 'Language',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Electronics': {\n id: 'subject.option.Electronics',\n defaultMessage: 'Electronics',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Food & Nutrition': {\n id: 'subject.option.Food & Nutrition',\n defaultMessage: 'Food & Nutrition',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Architecture': {\n id: 'subject.option.Architecture',\n defaultMessage: 'Architecture',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Chemistry': {\n id: 'subject.option.Chemistry',\n defaultMessage: 'Chemistry',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Literature': {\n id: 'subject.option.Literature',\n defaultMessage: 'Literature',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Ethics': {\n id: 'subject.option.Ethics',\n defaultMessage: 'Ethics',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Music': {\n id: 'subject.option.Music',\n defaultMessage: 'Music',\n description: 'Option for the subject dropdown field',\n },\n 'subject.option.Philanthropy': {\n id: 'subject.option.Philanthropy',\n defaultMessage: 'Philanthropy',\n description: 'Option for the subject dropdown field',\n },\n // Level of Education Options\n 'levelOfEducation.option.none': {\n id: 'levelOfEducation.option.none',\n defaultMessage: 'No formal education',\n description: 'Option for education level field',\n },\n 'levelOfEducation.option.jhs': {\n id: 'levelOfEducation.option.jhs',\n defaultMessage: 'Junior secondary/junior high/middle school',\n description: 'Option for education level field',\n },\n 'levelOfEducation.option.hs': {\n id: 'levelOfEducation.option.hs',\n defaultMessage: 'Secondary/High School',\n description: 'Option for education level field',\n },\n 'levelOfEducation.option.a': {\n id: 'levelOfEducation.option.a',\n defaultMessage: 'Associate Degree',\n description: 'Option for education level field',\n },\n 'levelOfEducation.option.b': {\n id: 'levelOfEducation.option.b',\n defaultMessage: 'Bachelor\\'s Degree',\n description: 'Option for education level field',\n },\n 'levelOfEducation.option.m': {\n id: 'levelOfEducation.option.m',\n defaultMessage: 'Master\\'s or professional degree',\n description: 'Option for education level field',\n },\n 'levelOfEducation.option.p': {\n id: 'levelOfEducation.option.p',\n defaultMessage: 'Doctorate',\n description: 'Option for education level field',\n },\n 'levelOfEducation.option.other': {\n id: 'levelOfEducation.option.other',\n defaultMessage: 'Other',\n description: 'Option for education level field',\n },\n // Work Experience Options\n 'workExperience.option.0yrs': {\n id: 'workExperience.option.0yrs',\n defaultMessage: 'I don’t have any work experience',\n description: 'Option for work experience field',\n },\n 'workExperience.option.1-5yrs': {\n id: 'workExperience.option.1-5yrs',\n defaultMessage: 'I have 1-5 years of work experience',\n description: 'Option for work experience field',\n },\n 'workExperience.option.6-10yrs': {\n id: 'workExperience.option.6-10yrs',\n defaultMessage: 'I have 6-10 years of work experience',\n description: 'Option for work experience field',\n },\n 'workExperience.option.11-15yrs': {\n id: 'workExperience.option.11-15yrs',\n defaultMessage: 'I have 11-15 years of work experience',\n description: 'Option for work experience field',\n },\n 'workExperience.option.16-20yrs': {\n id: 'workExperience.option.16-20yrs',\n defaultMessage: 'I have 16-20 years of work experience',\n description: 'Option for work experience field',\n },\n 'workExperience.option.20+yrs': {\n id: 'workExperience.option.20+yrs',\n defaultMessage: 'More than 20 years of work experience',\n description: 'Option for work experience field',\n },\n // Learning Experience Options\n 'learningType.option.Courses': {\n id: 'learningType.option.Courses',\n defaultMessage: 'Courses',\n description: 'Option for learning type dropdown field',\n },\n 'learningType.option.Programs': {\n id: 'learningType.option.Programs',\n defaultMessage: 'Programs',\n description: 'Option for learning type dropdown field',\n },\n 'learningType.option.Boot Camps': {\n id: 'learningType.option.Boot Camps',\n defaultMessage: 'Boot Camps',\n description: 'Option for learning type dropdown field',\n },\n 'learningType.option.Degrees': {\n id: 'learningType.option.Degree Programs',\n defaultMessage: 'Degrees',\n description: 'Option for learning type dropdown field',\n },\n 'learningType.option.Executive Education': {\n id: 'learningType.option.Executive Education',\n defaultMessage: 'Executive Education',\n description: 'Option for learning type dropdown field',\n },\n 'learningType.option.unsure': {\n id: 'learningType.option.Unsure',\n defaultMessage: 'Unsure',\n description: 'Option for learning type dropdown field',\n },\n // Gender Options\n 'gender.option.m': {\n id: 'gender.option.m',\n defaultMessage: 'Male',\n description: 'Option for gender field',\n },\n 'gender.option.f': {\n id: 'gender.option.f',\n defaultMessage: 'Female',\n description: 'Option for gender field',\n },\n 'gender.option.o': {\n id: 'gender.option.o',\n defaultMessage: 'Other/prefer not to answer',\n description: 'Option for gender field',\n },\n});\n\nexport default messages;\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/registration-popup/components/RegistrationFailureAlert.js b/dist/forms/registration-popup/components/RegistrationFailureAlert.js new file mode 100644 index 00000000..588441a1 --- /dev/null +++ b/dist/forms/registration-popup/components/RegistrationFailureAlert.js @@ -0,0 +1,62 @@ +import React from 'react'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Alert } from '@openedx/paragon'; +import PropTypes from 'prop-types'; +import { FORBIDDEN_REQUEST, FORM_SUBMISSION_ERROR, INTERNAL_SERVER_ERROR, TPA_AUTHENTICATION_FAILURE, TPA_SESSION_EXPIRED } from '../../../data/constants'; +import messages from '../messages'; + +/** + * RegisterFailureAlert component that is responsible to show error alert based on error code. + * It accepts the following props + * @param context + * @param errorCode + */ + +const RegistrationFailureMessage = _ref => { + let { + context = { + errorMessage: null + }, + errorCode + } = _ref; + const { + formatMessage + } = useIntl(); + if (!errorCode || errorCode === TPA_AUTHENTICATION_FAILURE) { + return null; + } + let errorMessage; + switch (errorCode) { + case INTERNAL_SERVER_ERROR: + errorMessage = formatMessage(messages.registrationRequestServerError); + break; + case FORBIDDEN_REQUEST: + errorMessage = formatMessage(messages.registrationRateLimitError); + break; + case TPA_SESSION_EXPIRED: + errorMessage = formatMessage(messages.registrationTPASessionExpired, { + provider: context.provider + }); + break; + case FORM_SUBMISSION_ERROR: + errorMessage = formatMessage(messages.registrationFormSubmissionError); + break; + default: + errorMessage = formatMessage(messages.registrationEmptyFormSubmissionError); + break; + } + return /*#__PURE__*/React.createElement(Alert, { + id: "registration-failure-alert", + className: "mb-5", + variant: "danger" + }, /*#__PURE__*/React.createElement("p", null, errorMessage)); +}; +RegistrationFailureMessage.propTypes = { + context: PropTypes.shape({ + provider: PropTypes.string, + errorMessage: PropTypes.string + }), + errorCode: PropTypes.string.isRequired +}; +export default RegistrationFailureMessage; +//# sourceMappingURL=RegistrationFailureAlert.js.map \ No newline at end of file diff --git a/dist/forms/registration-popup/components/RegistrationFailureAlert.js.map b/dist/forms/registration-popup/components/RegistrationFailureAlert.js.map new file mode 100644 index 00000000..13eb2401 --- /dev/null +++ b/dist/forms/registration-popup/components/RegistrationFailureAlert.js.map @@ -0,0 +1 @@ +{"version":3,"file":"RegistrationFailureAlert.js","names":["React","useIntl","Alert","PropTypes","FORBIDDEN_REQUEST","FORM_SUBMISSION_ERROR","INTERNAL_SERVER_ERROR","TPA_AUTHENTICATION_FAILURE","TPA_SESSION_EXPIRED","messages","RegistrationFailureMessage","_ref","context","errorMessage","errorCode","formatMessage","registrationRequestServerError","registrationRateLimitError","registrationTPASessionExpired","provider","registrationFormSubmissionError","registrationEmptyFormSubmissionError","createElement","id","className","variant","propTypes","shape","string","isRequired"],"sources":["../../../../src/forms/registration-popup/components/RegistrationFailureAlert.jsx"],"sourcesContent":["import React from 'react';\n\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport { Alert } from '@openedx/paragon';\nimport PropTypes from 'prop-types';\n\nimport {\n FORBIDDEN_REQUEST,\n FORM_SUBMISSION_ERROR,\n INTERNAL_SERVER_ERROR,\n TPA_AUTHENTICATION_FAILURE,\n TPA_SESSION_EXPIRED,\n} from '../../../data/constants';\nimport messages from '../messages';\n\n/**\n * RegisterFailureAlert component that is responsible to show error alert based on error code.\n * It accepts the following props\n * @param context\n * @param errorCode\n */\n\nconst RegistrationFailureMessage = ({\n context = {\n errorMessage: null,\n }, errorCode,\n}) => {\n const { formatMessage } = useIntl();\n\n if (!errorCode || errorCode === TPA_AUTHENTICATION_FAILURE) {\n return null;\n }\n\n let errorMessage;\n switch (errorCode) {\n case INTERNAL_SERVER_ERROR:\n errorMessage = formatMessage(messages.registrationRequestServerError);\n break;\n case FORBIDDEN_REQUEST:\n errorMessage = formatMessage(messages.registrationRateLimitError);\n break;\n case TPA_SESSION_EXPIRED:\n errorMessage = formatMessage(messages.registrationTPASessionExpired, { provider: context.provider });\n break;\n case FORM_SUBMISSION_ERROR:\n errorMessage = formatMessage(messages.registrationFormSubmissionError);\n break;\n default:\n errorMessage = formatMessage(messages.registrationEmptyFormSubmissionError);\n break;\n }\n\n return (\n \n

{errorMessage}

\n
\n );\n};\n\nRegistrationFailureMessage.propTypes = {\n context: PropTypes.shape({\n provider: PropTypes.string,\n errorMessage: PropTypes.string,\n }),\n errorCode: PropTypes.string.isRequired,\n};\n\nexport default RegistrationFailureMessage;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AAEzB,SAASC,OAAO,QAAQ,6BAA6B;AACrD,SAASC,KAAK,QAAQ,kBAAkB;AACxC,OAAOC,SAAS,MAAM,YAAY;AAElC,SACEC,iBAAiB,EACjBC,qBAAqB,EACrBC,qBAAqB,EACrBC,0BAA0B,EAC1BC,mBAAmB,QACd,yBAAyB;AAChC,OAAOC,QAAQ,MAAM,aAAa;;AAElC;AACA;AACA;AACA;AACA;AACA;;AAEA,MAAMC,0BAA0B,GAAGC,IAAA,IAI7B;EAAA,IAJ8B;IAClCC,OAAO,GAAG;MACRC,YAAY,EAAE;IAChB,CAAC;IAAEC;EACL,CAAC,GAAAH,IAAA;EACC,MAAM;IAAEI;EAAc,CAAC,GAAGd,OAAO,CAAC,CAAC;EAEnC,IAAI,CAACa,SAAS,IAAIA,SAAS,KAAKP,0BAA0B,EAAE;IAC1D,OAAO,IAAI;EACb;EAEA,IAAIM,YAAY;EAChB,QAAQC,SAAS;IACf,KAAKR,qBAAqB;MACxBO,YAAY,GAAGE,aAAa,CAACN,QAAQ,CAACO,8BAA8B,CAAC;MACtE;IACD,KAAKZ,iBAAiB;MACpBS,YAAY,GAAGE,aAAa,CAACN,QAAQ,CAACQ,0BAA0B,CAAC;MACjE;IACF,KAAKT,mBAAmB;MACtBK,YAAY,GAAGE,aAAa,CAACN,QAAQ,CAACS,6BAA6B,EAAE;QAAEC,QAAQ,EAAEP,OAAO,CAACO;MAAS,CAAC,CAAC;MACpG;IACF,KAAKd,qBAAqB;MACxBQ,YAAY,GAAGE,aAAa,CAACN,QAAQ,CAACW,+BAA+B,CAAC;MACtE;IACF;MACEP,YAAY,GAAGE,aAAa,CAACN,QAAQ,CAACY,oCAAoC,CAAC;MAC3E;EACJ;EAEA,oBACErB,KAAA,CAAAsB,aAAA,CAACpB,KAAK;IAACqB,EAAE,EAAC,4BAA4B;IAACC,SAAS,EAAC,MAAM;IAACC,OAAO,EAAC;EAAQ,gBACtEzB,KAAA,CAAAsB,aAAA,YAAIT,YAAgB,CACf,CAAC;AAEZ,CAAC;AAEDH,0BAA0B,CAACgB,SAAS,GAAG;EACrCd,OAAO,EAAET,SAAS,CAACwB,KAAK,CAAC;IACvBR,QAAQ,EAAEhB,SAAS,CAACyB,MAAM;IAC1Bf,YAAY,EAAEV,SAAS,CAACyB;EAC1B,CAAC,CAAC;EACFd,SAAS,EAAEX,SAAS,CAACyB,MAAM,CAACC;AAC9B,CAAC;AAED,eAAenB,0BAA0B","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/registration-popup/components/honorCodeAndTOS.js b/dist/forms/registration-popup/components/honorCodeAndTOS.js new file mode 100644 index 00000000..fbf15bc8 --- /dev/null +++ b/dist/forms/registration-popup/components/honorCodeAndTOS.js @@ -0,0 +1,33 @@ +import React from 'react'; +import { getConfig } from '@edx/frontend-platform'; +import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; +import { Hyperlink } from '@openedx/paragon'; +import messages from '../messages'; +const HonorCodeAndPrivacyPolicyMessage = () => { + const { + formatMessage + } = useIntl(); + return /*#__PURE__*/React.createElement(FormattedMessage, { + id: "register.page.terms.of.service.and.honor.code", + defaultMessage: "By creating an account, you agree to the {TOSAndHonorCode} and you acknowledge that edX and each Member process your personal data in accordance with the {privacyPolicy}.", + description: "Text that appears on registration form stating edX's honor code and privacy policy", + values: { + TOSAndHonorCode: /*#__PURE__*/React.createElement(Hyperlink, { + className: "text-white registration-form__tos-and-privacy-policy__link", + destination: getConfig().TOS_AND_HONOR_CODE, + target: "_blank", + showLaunchIcon: false, + isInline: true + }, formatMessage(messages.registrationFormTermsOfServiceAndHonorCodeLabel)), + privacyPolicy: /*#__PURE__*/React.createElement(Hyperlink, { + className: "text-white registration-form__tos-and-privacy-policy__link", + destination: getConfig().PRIVACY_POLICY, + target: "_blank", + showLaunchIcon: false, + isInline: true + }, formatMessage(messages.registrationFormPrivacyPolicyLabel)) + } + }); +}; +export default HonorCodeAndPrivacyPolicyMessage; +//# sourceMappingURL=honorCodeAndTOS.js.map \ No newline at end of file diff --git a/dist/forms/registration-popup/components/honorCodeAndTOS.js.map b/dist/forms/registration-popup/components/honorCodeAndTOS.js.map new file mode 100644 index 00000000..9aae7eae --- /dev/null +++ b/dist/forms/registration-popup/components/honorCodeAndTOS.js.map @@ -0,0 +1 @@ +{"version":3,"file":"honorCodeAndTOS.js","names":["React","getConfig","FormattedMessage","useIntl","Hyperlink","messages","HonorCodeAndPrivacyPolicyMessage","formatMessage","createElement","id","defaultMessage","description","values","TOSAndHonorCode","className","destination","TOS_AND_HONOR_CODE","target","showLaunchIcon","isInline","registrationFormTermsOfServiceAndHonorCodeLabel","privacyPolicy","PRIVACY_POLICY","registrationFormPrivacyPolicyLabel"],"sources":["../../../../src/forms/registration-popup/components/honorCodeAndTOS.jsx"],"sourcesContent":["import React from 'react';\n\nimport { getConfig } from '@edx/frontend-platform';\nimport { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';\nimport { Hyperlink } from '@openedx/paragon';\n\nimport messages from '../messages';\n\nconst HonorCodeAndPrivacyPolicyMessage = () => {\n const { formatMessage } = useIntl();\n\n return (\n \n {formatMessage(messages.registrationFormTermsOfServiceAndHonorCodeLabel)}\n \n ),\n privacyPolicy: (\n \n {formatMessage(messages.registrationFormPrivacyPolicyLabel)}\n \n ),\n }}\n />\n );\n};\n\nexport default HonorCodeAndPrivacyPolicyMessage;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AAEzB,SAASC,SAAS,QAAQ,wBAAwB;AAClD,SAASC,gBAAgB,EAAEC,OAAO,QAAQ,6BAA6B;AACvE,SAASC,SAAS,QAAQ,kBAAkB;AAE5C,OAAOC,QAAQ,MAAM,aAAa;AAElC,MAAMC,gCAAgC,GAAGA,CAAA,KAAM;EAC7C,MAAM;IAAEC;EAAc,CAAC,GAAGJ,OAAO,CAAC,CAAC;EAEnC,oBACEH,KAAA,CAAAQ,aAAA,CAACN,gBAAgB;IACfO,EAAE,EAAC,+CAA+C;IAClDC,cAAc,EAAC,4KAEkB;IACjCC,WAAW,EAAC,oFAAoF;IAChGC,MAAM,EAAE;MACNC,eAAe,eACbb,KAAA,CAAAQ,aAAA,CAACJ,SAAS;QACRU,SAAS,EAAC,4DAA4D;QACtEC,WAAW,EAAEd,SAAS,CAAC,CAAC,CAACe,kBAAmB;QAC5CC,MAAM,EAAC,QAAQ;QACfC,cAAc,EAAE,KAAM;QACtBC,QAAQ;MAAA,GAEPZ,aAAa,CAACF,QAAQ,CAACe,+CAA+C,CAC9D,CACZ;MACDC,aAAa,eACXrB,KAAA,CAAAQ,aAAA,CAACJ,SAAS;QACRU,SAAS,EAAC,4DAA4D;QACtEC,WAAW,EAAEd,SAAS,CAAC,CAAC,CAACqB,cAAe;QACxCL,MAAM,EAAC,QAAQ;QACfC,cAAc,EAAE,KAAM;QACtBC,QAAQ;MAAA,GAEPZ,aAAa,CAACF,QAAQ,CAACkB,kCAAkC,CACjD;IAEf;EAAE,CACH,CAAC;AAEN,CAAC;AAED,eAAejB,gCAAgC","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/registration-popup/data/constants.js b/dist/forms/registration-popup/data/constants.js new file mode 100644 index 00000000..28e060b1 --- /dev/null +++ b/dist/forms/registration-popup/data/constants.js @@ -0,0 +1,5 @@ +const LETTER_REGEX = /[a-zA-Z]/; +const NUMBER_REGEX = /\d/; +export const VALID_EMAIL_REGEX = '(^[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+(\\.[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+)*' + '|^"([\\001-\\010\\013\\014\\016-\\037!#-\\[\\]-\\177]|\\\\[\\001-\\011\\013\\014\\016-\\177])*"' + ')@((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\\.)+)(?:[A-Z0-9-]{2,63})' + '|\\[(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\]$'; +export { LETTER_REGEX, NUMBER_REGEX }; +//# sourceMappingURL=constants.js.map \ No newline at end of file diff --git a/dist/forms/registration-popup/data/constants.js.map b/dist/forms/registration-popup/data/constants.js.map new file mode 100644 index 00000000..3754eff9 --- /dev/null +++ b/dist/forms/registration-popup/data/constants.js.map @@ -0,0 +1 @@ +{"version":3,"file":"constants.js","names":["LETTER_REGEX","NUMBER_REGEX","VALID_EMAIL_REGEX"],"sources":["../../../../src/forms/registration-popup/data/constants.js"],"sourcesContent":["const LETTER_REGEX = /[a-zA-Z]/;\nconst NUMBER_REGEX = /\\d/;\n\nexport const VALID_EMAIL_REGEX = '(^[-!#$%&\\'*+/=?^_`{}|~0-9A-Z]+(\\\\.[-!#$%&\\'*+/=?^_`{}|~0-9A-Z]+)*'\n + '|^\"([\\\\001-\\\\010\\\\013\\\\014\\\\016-\\\\037!#-\\\\[\\\\]-\\\\177]|\\\\\\\\[\\\\001-\\\\011\\\\013\\\\014\\\\016-\\\\177])*\"'\n + ')@((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\\\\.)+)(?:[A-Z0-9-]{2,63})'\n + '|\\\\[(25[0-5]|2[0-4]\\\\d|[0-1]?\\\\d?\\\\d)(\\\\.(25[0-5]|2[0-4]\\\\d|[0-1]?\\\\d?\\\\d)){3}\\\\]$';\n\nexport {\n LETTER_REGEX, NUMBER_REGEX,\n};\n"],"mappings":"AAAA,MAAMA,YAAY,GAAG,UAAU;AAC/B,MAAMC,YAAY,GAAG,IAAI;AAEzB,OAAO,MAAMC,iBAAiB,GAAG,oEAAoE,GAClE,iGAAiG,GACjG,qEAAqE,GACrE,oFAAoF;AAEvH,SACEF,YAAY,EAAEC,YAAY","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/registration-popup/data/reducers.js b/dist/forms/registration-popup/data/reducers.js new file mode 100644 index 00000000..3996b139 --- /dev/null +++ b/dist/forms/registration-popup/data/reducers.js @@ -0,0 +1,95 @@ +/** + * Redux slice for managing registration state. + * This slice handles the registration process, including the submission state, + * registration result, and any registration errors. + */ + +import { createSlice } from '@reduxjs/toolkit'; +import { COMPLETE_STATE, DEFAULT_STATE, PENDING_STATE } from '../../../data/constants'; +export const storeName = 'register'; +export const REGISTER_SLICE_NAME = 'register'; +export const registerInitialState = { + submitState: DEFAULT_STATE, + validationState: DEFAULT_STATE, + registrationError: {}, + registrationResult: {}, + registrationFields: { + marketingEmailsOptIn: true + }, + userPipelineDataLoaded: false, + validationApiRateLimited: false, + validations: null +}; +export const registerSlice = createSlice({ + name: REGISTER_SLICE_NAME, + initialState: registerInitialState, + reducers: { + registerUser: state => { + state.submitState = PENDING_STATE; + state.registrationError = {}; + }, + registerUserSuccess: (state, _ref) => { + let { + payload + } = _ref; + state.submitState = COMPLETE_STATE; + state.registrationResult = payload; + }, + registerUserFailed: (state, _ref2) => { + let { + payload + } = _ref2; + state.registrationError = payload; + state.registrationResult = {}; + state.validations = null; + state.submitState = DEFAULT_STATE; + }, + fetchRealtimeValidations: state => { + state.validationState = PENDING_STATE; + state.validations = null; + }, + fetchRealtimeValidationsSuccess: (state, _ref3) => { + let { + payload + } = _ref3; + state.validationState = COMPLETE_STATE; + state.validations = payload; + }, + fetchRealtimeValidationsFailed: state => { + state.validationApiRateLimited = true; + state.validations = null; + state.validationState = DEFAULT_STATE; + }, + clearRegistrationBackendError: (state, _ref4) => { + let { + payload + } = _ref4; + const registrationErrorTemp = state.registrationError; + delete registrationErrorTemp[payload]; + state.registrationError = registrationErrorTemp; + }, + clearAllRegistrationErrors: state => { + state.registrationError = {}; + state.validations = null; + }, + setRegistrationFields: (state, _ref5) => { + let { + payload + } = _ref5; + state.registrationFields = payload; + } + } +}); +export const { + registerUser, + registerUserSuccess, + registerUserFailed, + setRegistrationFields, + fetchRealtimeValidations, + fetchRealtimeValidationsSuccess, + fetchRealtimeValidationsFailed, + clearAllRegistrationErrors, + clearRegistrationBackendError +} = registerSlice.actions; +export default registerSlice.reducer; +//# sourceMappingURL=reducers.js.map \ No newline at end of file diff --git a/dist/forms/registration-popup/data/reducers.js.map b/dist/forms/registration-popup/data/reducers.js.map new file mode 100644 index 00000000..875b22f8 --- /dev/null +++ b/dist/forms/registration-popup/data/reducers.js.map @@ -0,0 +1 @@ +{"version":3,"file":"reducers.js","names":["createSlice","COMPLETE_STATE","DEFAULT_STATE","PENDING_STATE","storeName","REGISTER_SLICE_NAME","registerInitialState","submitState","validationState","registrationError","registrationResult","registrationFields","marketingEmailsOptIn","userPipelineDataLoaded","validationApiRateLimited","validations","registerSlice","name","initialState","reducers","registerUser","state","registerUserSuccess","_ref","payload","registerUserFailed","_ref2","fetchRealtimeValidations","fetchRealtimeValidationsSuccess","_ref3","fetchRealtimeValidationsFailed","clearRegistrationBackendError","_ref4","registrationErrorTemp","clearAllRegistrationErrors","setRegistrationFields","_ref5","actions","reducer"],"sources":["../../../../src/forms/registration-popup/data/reducers.js"],"sourcesContent":["/**\n * Redux slice for managing registration state.\n * This slice handles the registration process, including the submission state,\n * registration result, and any registration errors.\n */\n\nimport { createSlice } from '@reduxjs/toolkit';\n\nimport { COMPLETE_STATE, DEFAULT_STATE, PENDING_STATE } from '../../../data/constants';\n\nexport const storeName = 'register';\nexport const REGISTER_SLICE_NAME = 'register';\n\nexport const registerInitialState = {\n submitState: DEFAULT_STATE,\n validationState: DEFAULT_STATE,\n registrationError: {},\n registrationResult: {},\n registrationFields: { marketingEmailsOptIn: true },\n userPipelineDataLoaded: false,\n validationApiRateLimited: false,\n validations: null,\n};\n\nexport const registerSlice = createSlice({\n name: REGISTER_SLICE_NAME,\n initialState: registerInitialState,\n reducers: {\n registerUser: (state) => {\n state.submitState = PENDING_STATE;\n state.registrationError = {};\n },\n registerUserSuccess: (state, { payload }) => {\n state.submitState = COMPLETE_STATE;\n state.registrationResult = payload;\n },\n registerUserFailed: (state, { payload }) => {\n state.registrationError = payload;\n state.registrationResult = {};\n state.validations = null;\n state.submitState = DEFAULT_STATE;\n },\n fetchRealtimeValidations: (state) => {\n state.validationState = PENDING_STATE;\n state.validations = null;\n },\n fetchRealtimeValidationsSuccess: (state, { payload }) => {\n state.validationState = COMPLETE_STATE;\n state.validations = payload;\n },\n fetchRealtimeValidationsFailed: (state) => {\n state.validationApiRateLimited = true;\n state.validations = null;\n state.validationState = DEFAULT_STATE;\n },\n clearRegistrationBackendError: (state, { payload }) => {\n const registrationErrorTemp = state.registrationError;\n delete registrationErrorTemp[payload];\n state.registrationError = registrationErrorTemp;\n },\n clearAllRegistrationErrors: (state) => {\n state.registrationError = {};\n state.validations = null;\n },\n setRegistrationFields: (state, { payload }) => {\n state.registrationFields = payload;\n },\n },\n});\n\nexport const {\n registerUser,\n registerUserSuccess,\n registerUserFailed,\n setRegistrationFields,\n fetchRealtimeValidations,\n fetchRealtimeValidationsSuccess,\n fetchRealtimeValidationsFailed,\n clearAllRegistrationErrors,\n clearRegistrationBackendError,\n} = registerSlice.actions;\n\nexport default registerSlice.reducer;\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;;AAEA,SAASA,WAAW,QAAQ,kBAAkB;AAE9C,SAASC,cAAc,EAAEC,aAAa,EAAEC,aAAa,QAAQ,yBAAyB;AAEtF,OAAO,MAAMC,SAAS,GAAG,UAAU;AACnC,OAAO,MAAMC,mBAAmB,GAAG,UAAU;AAE7C,OAAO,MAAMC,oBAAoB,GAAG;EAClCC,WAAW,EAAEL,aAAa;EAC1BM,eAAe,EAAEN,aAAa;EAC9BO,iBAAiB,EAAE,CAAC,CAAC;EACrBC,kBAAkB,EAAE,CAAC,CAAC;EACtBC,kBAAkB,EAAE;IAAEC,oBAAoB,EAAE;EAAK,CAAC;EAClDC,sBAAsB,EAAE,KAAK;EAC7BC,wBAAwB,EAAE,KAAK;EAC/BC,WAAW,EAAE;AACf,CAAC;AAED,OAAO,MAAMC,aAAa,GAAGhB,WAAW,CAAC;EACvCiB,IAAI,EAAEZ,mBAAmB;EACzBa,YAAY,EAAEZ,oBAAoB;EAClCa,QAAQ,EAAE;IACRC,YAAY,EAAGC,KAAK,IAAK;MACvBA,KAAK,CAACd,WAAW,GAAGJ,aAAa;MACjCkB,KAAK,CAACZ,iBAAiB,GAAG,CAAC,CAAC;IAC9B,CAAC;IACDa,mBAAmB,EAAEA,CAACD,KAAK,EAAAE,IAAA,KAAkB;MAAA,IAAhB;QAAEC;MAAQ,CAAC,GAAAD,IAAA;MACtCF,KAAK,CAACd,WAAW,GAAGN,cAAc;MAClCoB,KAAK,CAACX,kBAAkB,GAAGc,OAAO;IACpC,CAAC;IACDC,kBAAkB,EAAEA,CAACJ,KAAK,EAAAK,KAAA,KAAkB;MAAA,IAAhB;QAAEF;MAAQ,CAAC,GAAAE,KAAA;MACrCL,KAAK,CAACZ,iBAAiB,GAAGe,OAAO;MACjCH,KAAK,CAACX,kBAAkB,GAAG,CAAC,CAAC;MAC7BW,KAAK,CAACN,WAAW,GAAG,IAAI;MACxBM,KAAK,CAACd,WAAW,GAAGL,aAAa;IACnC,CAAC;IACDyB,wBAAwB,EAAGN,KAAK,IAAK;MACnCA,KAAK,CAACb,eAAe,GAAGL,aAAa;MACrCkB,KAAK,CAACN,WAAW,GAAG,IAAI;IAC1B,CAAC;IACDa,+BAA+B,EAAEA,CAACP,KAAK,EAAAQ,KAAA,KAAkB;MAAA,IAAhB;QAAEL;MAAQ,CAAC,GAAAK,KAAA;MAClDR,KAAK,CAACb,eAAe,GAAGP,cAAc;MACtCoB,KAAK,CAACN,WAAW,GAAGS,OAAO;IAC7B,CAAC;IACDM,8BAA8B,EAAGT,KAAK,IAAK;MACzCA,KAAK,CAACP,wBAAwB,GAAG,IAAI;MACrCO,KAAK,CAACN,WAAW,GAAG,IAAI;MACxBM,KAAK,CAACb,eAAe,GAAGN,aAAa;IACvC,CAAC;IACD6B,6BAA6B,EAAEA,CAACV,KAAK,EAAAW,KAAA,KAAkB;MAAA,IAAhB;QAAER;MAAQ,CAAC,GAAAQ,KAAA;MAChD,MAAMC,qBAAqB,GAAGZ,KAAK,CAACZ,iBAAiB;MACrD,OAAOwB,qBAAqB,CAACT,OAAO,CAAC;MACrCH,KAAK,CAACZ,iBAAiB,GAAGwB,qBAAqB;IACjD,CAAC;IACDC,0BAA0B,EAAGb,KAAK,IAAK;MACrCA,KAAK,CAACZ,iBAAiB,GAAG,CAAC,CAAC;MAC5BY,KAAK,CAACN,WAAW,GAAG,IAAI;IAC1B,CAAC;IACDoB,qBAAqB,EAAEA,CAACd,KAAK,EAAAe,KAAA,KAAkB;MAAA,IAAhB;QAAEZ;MAAQ,CAAC,GAAAY,KAAA;MACxCf,KAAK,CAACV,kBAAkB,GAAGa,OAAO;IACpC;EACF;AACF,CAAC,CAAC;AAEF,OAAO,MAAM;EACXJ,YAAY;EACZE,mBAAmB;EACnBG,kBAAkB;EAClBU,qBAAqB;EACrBR,wBAAwB;EACxBC,+BAA+B;EAC/BE,8BAA8B;EAC9BI,0BAA0B;EAC1BH;AACF,CAAC,GAAGf,aAAa,CAACqB,OAAO;AAEzB,eAAerB,aAAa,CAACsB,OAAO","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/registration-popup/data/sagas.js b/dist/forms/registration-popup/data/sagas.js new file mode 100644 index 00000000..234a470c --- /dev/null +++ b/dist/forms/registration-popup/data/sagas.js @@ -0,0 +1,66 @@ +import { camelCaseObject } from '@edx/frontend-platform'; +import { logError, logInfo } from '@edx/frontend-platform/logging'; +import { call, put, takeEvery } from 'redux-saga/effects'; +import { fetchRealtimeValidations, fetchRealtimeValidationsFailed, fetchRealtimeValidationsSuccess, registerUser, registerUserFailed, registerUserSuccess } from './reducers'; +import registerRequest, { getFieldsValidations } from './service'; +import { INTERNAL_SERVER_ERROR } from '../../../data/constants'; + +/** + * Saga function for handling new user registration. + * @param {object} action - The Redux action object containing the payload. + */ +export function* handleNewUserRegistration(action) { + try { + const { + authenticatedUser, + redirectUrl, + success + } = yield call(registerRequest, action.payload); + yield put(registerUserSuccess({ + authenticatedUser: camelCaseObject(authenticatedUser), + redirectUrl, + success + })); + } catch (e) { + const statusCodes = [400, 403, 409]; + if (e.response && statusCodes.includes(e.response.status)) { + yield put(registerUserFailed(camelCaseObject(e.response.data))); + logInfo(e); + } else { + yield put(registerUserFailed({ + errorCode: INTERNAL_SERVER_ERROR + })); + logError(e); + } + } +} + +/** + * Saga function for handling new validations. + * @param {object} action - The Redux action object containing the payload. + */ +export function* fetchValidationsSaga(action) { + try { + const { + fieldValidations + } = yield call(getFieldsValidations, action.payload); + yield put(fetchRealtimeValidationsSuccess(camelCaseObject(fieldValidations))); + } catch (e) { + if (e.response && e.response.status === 403) { + yield put(fetchRealtimeValidationsFailed()); + logInfo(e); + } else { + logError(e); + } + } +} + +/** + * Root Saga function that listens for REGISTER actions and calls the handleNewUserRegistration saga + * and fetchValidationsSaga. + */ +export default function* saga() { + yield takeEvery(registerUser.type, handleNewUserRegistration); + yield takeEvery(fetchRealtimeValidations.type, fetchValidationsSaga); +} +//# sourceMappingURL=sagas.js.map \ No newline at end of file diff --git a/dist/forms/registration-popup/data/sagas.js.map b/dist/forms/registration-popup/data/sagas.js.map new file mode 100644 index 00000000..ab84dda5 --- /dev/null +++ b/dist/forms/registration-popup/data/sagas.js.map @@ -0,0 +1 @@ +{"version":3,"file":"sagas.js","names":["camelCaseObject","logError","logInfo","call","put","takeEvery","fetchRealtimeValidations","fetchRealtimeValidationsFailed","fetchRealtimeValidationsSuccess","registerUser","registerUserFailed","registerUserSuccess","registerRequest","getFieldsValidations","INTERNAL_SERVER_ERROR","handleNewUserRegistration","action","authenticatedUser","redirectUrl","success","payload","e","statusCodes","response","includes","status","data","errorCode","fetchValidationsSaga","fieldValidations","saga","type"],"sources":["../../../../src/forms/registration-popup/data/sagas.js"],"sourcesContent":["import { camelCaseObject } from '@edx/frontend-platform';\nimport { logError, logInfo } from '@edx/frontend-platform/logging';\nimport { call, put, takeEvery } from 'redux-saga/effects';\n\nimport {\n fetchRealtimeValidations, fetchRealtimeValidationsFailed, fetchRealtimeValidationsSuccess,\n registerUser, registerUserFailed, registerUserSuccess,\n} from './reducers';\nimport registerRequest, { getFieldsValidations } from './service';\nimport { INTERNAL_SERVER_ERROR } from '../../../data/constants';\n\n/**\n * Saga function for handling new user registration.\n * @param {object} action - The Redux action object containing the payload.\n */\nexport function* handleNewUserRegistration(action) {\n try {\n const {\n authenticatedUser, redirectUrl, success,\n } = yield call(registerRequest, action.payload);\n\n yield put(registerUserSuccess({\n authenticatedUser: camelCaseObject(authenticatedUser),\n redirectUrl,\n success,\n }));\n } catch (e) {\n const statusCodes = [400, 403, 409];\n if (e.response && statusCodes.includes(e.response.status)) {\n yield put(registerUserFailed(camelCaseObject(e.response.data)));\n logInfo(e);\n } else {\n yield put(registerUserFailed({ errorCode: INTERNAL_SERVER_ERROR }));\n logError(e);\n }\n }\n}\n\n/**\n * Saga function for handling new validations.\n * @param {object} action - The Redux action object containing the payload.\n */\nexport function* fetchValidationsSaga(action) {\n try {\n const { fieldValidations } = yield call(getFieldsValidations, action.payload);\n\n yield put(fetchRealtimeValidationsSuccess(camelCaseObject(fieldValidations)));\n } catch (e) {\n if (e.response && e.response.status === 403) {\n yield put(fetchRealtimeValidationsFailed());\n logInfo(e);\n } else {\n logError(e);\n }\n }\n}\n\n/**\n * Root Saga function that listens for REGISTER actions and calls the handleNewUserRegistration saga\n * and fetchValidationsSaga.\n */\nexport default function* saga() {\n yield takeEvery(registerUser.type, handleNewUserRegistration);\n yield takeEvery(fetchRealtimeValidations.type, fetchValidationsSaga);\n}\n"],"mappings":"AAAA,SAASA,eAAe,QAAQ,wBAAwB;AACxD,SAASC,QAAQ,EAAEC,OAAO,QAAQ,gCAAgC;AAClE,SAASC,IAAI,EAAEC,GAAG,EAAEC,SAAS,QAAQ,oBAAoB;AAEzD,SACEC,wBAAwB,EAAEC,8BAA8B,EAAEC,+BAA+B,EACzFC,YAAY,EAAEC,kBAAkB,EAAEC,mBAAmB,QAChD,YAAY;AACnB,OAAOC,eAAe,IAAIC,oBAAoB,QAAQ,WAAW;AACjE,SAASC,qBAAqB,QAAQ,yBAAyB;;AAE/D;AACA;AACA;AACA;AACA,OAAO,UAAUC,yBAAyBA,CAACC,MAAM,EAAE;EACjD,IAAI;IACF,MAAM;MACJC,iBAAiB;MAAEC,WAAW;MAAEC;IAClC,CAAC,GAAG,MAAMhB,IAAI,CAACS,eAAe,EAAEI,MAAM,CAACI,OAAO,CAAC;IAE/C,MAAMhB,GAAG,CAACO,mBAAmB,CAAC;MAC5BM,iBAAiB,EAAEjB,eAAe,CAACiB,iBAAiB,CAAC;MACrDC,WAAW;MACXC;IACF,CAAC,CAAC,CAAC;EACL,CAAC,CAAC,OAAOE,CAAC,EAAE;IACV,MAAMC,WAAW,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACnC,IAAID,CAAC,CAACE,QAAQ,IAAID,WAAW,CAACE,QAAQ,CAACH,CAAC,CAACE,QAAQ,CAACE,MAAM,CAAC,EAAE;MACzD,MAAMrB,GAAG,CAACM,kBAAkB,CAACV,eAAe,CAACqB,CAAC,CAACE,QAAQ,CAACG,IAAI,CAAC,CAAC,CAAC;MAC/DxB,OAAO,CAACmB,CAAC,CAAC;IACZ,CAAC,MAAM;MACL,MAAMjB,GAAG,CAACM,kBAAkB,CAAC;QAAEiB,SAAS,EAAEb;MAAsB,CAAC,CAAC,CAAC;MACnEb,QAAQ,CAACoB,CAAC,CAAC;IACb;EACF;AACF;;AAEA;AACA;AACA;AACA;AACA,OAAO,UAAUO,oBAAoBA,CAACZ,MAAM,EAAE;EAC5C,IAAI;IACF,MAAM;MAAEa;IAAiB,CAAC,GAAG,MAAM1B,IAAI,CAACU,oBAAoB,EAAEG,MAAM,CAACI,OAAO,CAAC;IAE7E,MAAMhB,GAAG,CAACI,+BAA+B,CAACR,eAAe,CAAC6B,gBAAgB,CAAC,CAAC,CAAC;EAC/E,CAAC,CAAC,OAAOR,CAAC,EAAE;IACV,IAAIA,CAAC,CAACE,QAAQ,IAAIF,CAAC,CAACE,QAAQ,CAACE,MAAM,KAAK,GAAG,EAAE;MAC3C,MAAMrB,GAAG,CAACG,8BAA8B,CAAC,CAAC,CAAC;MAC3CL,OAAO,CAACmB,CAAC,CAAC;IACZ,CAAC,MAAM;MACLpB,QAAQ,CAACoB,CAAC,CAAC;IACb;EACF;AACF;;AAEA;AACA;AACA;AACA;AACA,eAAe,UAAUS,IAAIA,CAAA,EAAG;EAC9B,MAAMzB,SAAS,CAACI,YAAY,CAACsB,IAAI,EAAEhB,yBAAyB,CAAC;EAC7D,MAAMV,SAAS,CAACC,wBAAwB,CAACyB,IAAI,EAAEH,oBAAoB,CAAC;AACtE","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/registration-popup/data/selector.js b/dist/forms/registration-popup/data/selector.js new file mode 100644 index 00000000..b622fa02 --- /dev/null +++ b/dist/forms/registration-popup/data/selector.js @@ -0,0 +1,25 @@ +import { createSelector } from 'reselect'; + +/** + * Selector for backend validations which processes the api output and generates a + * key value dict for field errors. + * @returns {{username: string}|{name: string}|*|{}|null} + */ +const getRegistrationError = state => state.register.registrationError; +const getValidations = state => state.register.validations; +const getBackendValidations = createSelector([getRegistrationError, getValidations], (registrationError, validations) => { + if (validations) { + return validations.validationDecisions; + } + if (Object.keys(registrationError).length > 0) { + const fields = Object.keys(registrationError).filter(fieldName => !(fieldName in ['errorCode'])); + const validationDecisions = {}; + fields.forEach(field => { + validationDecisions[field] = registrationError[field][0].userMessage || ''; + }); + return validationDecisions; + } + return null; +}); +export default getBackendValidations; +//# sourceMappingURL=selector.js.map \ No newline at end of file diff --git a/dist/forms/registration-popup/data/selector.js.map b/dist/forms/registration-popup/data/selector.js.map new file mode 100644 index 00000000..e17868d6 --- /dev/null +++ b/dist/forms/registration-popup/data/selector.js.map @@ -0,0 +1 @@ +{"version":3,"file":"selector.js","names":["createSelector","getRegistrationError","state","register","registrationError","getValidations","validations","getBackendValidations","validationDecisions","Object","keys","length","fields","filter","fieldName","forEach","field","userMessage"],"sources":["../../../../src/forms/registration-popup/data/selector.js"],"sourcesContent":["import { createSelector } from 'reselect';\n\n/**\n * Selector for backend validations which processes the api output and generates a\n * key value dict for field errors.\n * @returns {{username: string}|{name: string}|*|{}|null}\n */\nconst getRegistrationError = state => state.register.registrationError;\nconst getValidations = state => state.register.validations;\n\nconst getBackendValidations = createSelector(\n [getRegistrationError, getValidations],\n (registrationError, validations) => {\n if (validations) {\n return validations.validationDecisions;\n }\n\n if (Object.keys(registrationError).length > 0) {\n const fields = Object.keys(registrationError).filter(\n (fieldName) => !(fieldName in ['errorCode']),\n );\n\n const validationDecisions = {};\n fields.forEach(field => {\n validationDecisions[field] = registrationError[field][0].userMessage || '';\n });\n return validationDecisions;\n }\n\n return null;\n },\n);\n\nexport default getBackendValidations;\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,UAAU;;AAEzC;AACA;AACA;AACA;AACA;AACA,MAAMC,oBAAoB,GAAGC,KAAK,IAAIA,KAAK,CAACC,QAAQ,CAACC,iBAAiB;AACtE,MAAMC,cAAc,GAAGH,KAAK,IAAIA,KAAK,CAACC,QAAQ,CAACG,WAAW;AAE1D,MAAMC,qBAAqB,GAAGP,cAAc,CAC1C,CAACC,oBAAoB,EAAEI,cAAc,CAAC,EACtC,CAACD,iBAAiB,EAAEE,WAAW,KAAK;EAClC,IAAIA,WAAW,EAAE;IACf,OAAOA,WAAW,CAACE,mBAAmB;EACxC;EAEA,IAAIC,MAAM,CAACC,IAAI,CAACN,iBAAiB,CAAC,CAACO,MAAM,GAAG,CAAC,EAAE;IAC7C,MAAMC,MAAM,GAAGH,MAAM,CAACC,IAAI,CAACN,iBAAiB,CAAC,CAACS,MAAM,CACjDC,SAAS,IAAK,EAAEA,SAAS,IAAI,CAAC,WAAW,CAAC,CAC7C,CAAC;IAED,MAAMN,mBAAmB,GAAG,CAAC,CAAC;IAC9BI,MAAM,CAACG,OAAO,CAACC,KAAK,IAAI;MACtBR,mBAAmB,CAACQ,KAAK,CAAC,GAAGZ,iBAAiB,CAACY,KAAK,CAAC,CAAC,CAAC,CAAC,CAACC,WAAW,IAAI,EAAE;IAC5E,CAAC,CAAC;IACF,OAAOT,mBAAmB;EAC5B;EAEA,OAAO,IAAI;AACb,CACF,CAAC;AAED,eAAeD,qBAAqB","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/registration-popup/data/service.js b/dist/forms/registration-popup/data/service.js new file mode 100644 index 00000000..c5320c03 --- /dev/null +++ b/dist/forms/registration-popup/data/service.js @@ -0,0 +1,45 @@ +import { getConfig } from '@edx/frontend-platform'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; +import QueryString from 'query-string'; + +/** + * Function for making a registration request to the server. + * This function sends a POST request to the registration endpoint with the provided registration information. + * @param {object} registrationInformation - The registration information to be sent to the server. + * @returns {object} An object containing the redirect URL, success status, and authenticated user details. + */ +export default async function registerRequest(registrationInformation) { + const requestConfig = { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + isPublic: true + }; + const { + data + } = await getAuthenticatedHttpClient().post(`${getConfig().LMS_BASE_URL}/api/user/v2/account/registration/`, QueryString.stringify(registrationInformation), requestConfig).catch(e => { + throw e; + }); + return { + redirectUrl: data.redirect_url || `${getConfig().LMS_BASE_URL}/dashboard`, + success: data.success || false, + authenticatedUser: data.authenticated_user + }; +} +export async function getFieldsValidations(formPayload) { + const requestConfig = { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + isPublic: true + }; + const { + data + } = await getAuthenticatedHttpClient().post(`${getConfig().LMS_BASE_URL}/api/user/v1/validation/registration`, QueryString.stringify(formPayload), requestConfig).catch(e => { + throw e; + }); + return { + fieldValidations: data + }; +} +//# sourceMappingURL=service.js.map \ No newline at end of file diff --git a/dist/forms/registration-popup/data/service.js.map b/dist/forms/registration-popup/data/service.js.map new file mode 100644 index 00000000..c3484617 --- /dev/null +++ b/dist/forms/registration-popup/data/service.js.map @@ -0,0 +1 @@ +{"version":3,"file":"service.js","names":["getConfig","getAuthenticatedHttpClient","QueryString","registerRequest","registrationInformation","requestConfig","headers","isPublic","data","post","LMS_BASE_URL","stringify","catch","e","redirectUrl","redirect_url","success","authenticatedUser","authenticated_user","getFieldsValidations","formPayload","fieldValidations"],"sources":["../../../../src/forms/registration-popup/data/service.js"],"sourcesContent":["import { getConfig } from '@edx/frontend-platform';\nimport { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';\nimport QueryString from 'query-string';\n\n/**\n * Function for making a registration request to the server.\n * This function sends a POST request to the registration endpoint with the provided registration information.\n * @param {object} registrationInformation - The registration information to be sent to the server.\n * @returns {object} An object containing the redirect URL, success status, and authenticated user details.\n */\nexport default async function registerRequest(registrationInformation) {\n const requestConfig = {\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n isPublic: true,\n };\n\n const { data } = await getAuthenticatedHttpClient()\n .post(\n `${getConfig().LMS_BASE_URL}/api/user/v2/account/registration/`,\n QueryString.stringify(registrationInformation),\n requestConfig,\n )\n .catch((e) => {\n throw (e);\n });\n\n return {\n redirectUrl: data.redirect_url || `${getConfig().LMS_BASE_URL}/dashboard`,\n success: data.success || false,\n authenticatedUser: data.authenticated_user,\n };\n}\n\nexport async function getFieldsValidations(formPayload) {\n const requestConfig = {\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n isPublic: true,\n };\n\n const { data } = await getAuthenticatedHttpClient()\n .post(\n `${getConfig().LMS_BASE_URL}/api/user/v1/validation/registration`,\n QueryString.stringify(formPayload),\n requestConfig,\n )\n .catch((e) => {\n throw (e);\n });\n\n return {\n fieldValidations: data,\n };\n}\n"],"mappings":"AAAA,SAASA,SAAS,QAAQ,wBAAwB;AAClD,SAASC,0BAA0B,QAAQ,6BAA6B;AACxE,OAAOC,WAAW,MAAM,cAAc;;AAEtC;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,eAAeC,eAAeA,CAACC,uBAAuB,EAAE;EACrE,MAAMC,aAAa,GAAG;IACpBC,OAAO,EAAE;MAAE,cAAc,EAAE;IAAoC,CAAC;IAChEC,QAAQ,EAAE;EACZ,CAAC;EAED,MAAM;IAAEC;EAAK,CAAC,GAAG,MAAMP,0BAA0B,CAAC,CAAC,CAChDQ,IAAI,CACF,GAAET,SAAS,CAAC,CAAC,CAACU,YAAa,oCAAmC,EAC/DR,WAAW,CAACS,SAAS,CAACP,uBAAuB,CAAC,EAC9CC,aACF,CAAC,CACAO,KAAK,CAAEC,CAAC,IAAK;IACZ,MAAOA,CAAC;EACV,CAAC,CAAC;EAEJ,OAAO;IACLC,WAAW,EAAEN,IAAI,CAACO,YAAY,IAAK,GAAEf,SAAS,CAAC,CAAC,CAACU,YAAa,YAAW;IACzEM,OAAO,EAAER,IAAI,CAACQ,OAAO,IAAI,KAAK;IAC9BC,iBAAiB,EAAET,IAAI,CAACU;EAC1B,CAAC;AACH;AAEA,OAAO,eAAeC,oBAAoBA,CAACC,WAAW,EAAE;EACtD,MAAMf,aAAa,GAAG;IACpBC,OAAO,EAAE;MAAE,cAAc,EAAE;IAAoC,CAAC;IAChEC,QAAQ,EAAE;EACZ,CAAC;EAED,MAAM;IAAEC;EAAK,CAAC,GAAG,MAAMP,0BAA0B,CAAC,CAAC,CAChDQ,IAAI,CACF,GAAET,SAAS,CAAC,CAAC,CAACU,YAAa,sCAAqC,EACjER,WAAW,CAACS,SAAS,CAACS,WAAW,CAAC,EAClCf,aACF,CAAC,CACAO,KAAK,CAAEC,CAAC,IAAK;IACZ,MAAOA,CAAC;EACV,CAAC,CAAC;EAEJ,OAAO;IACLQ,gBAAgB,EAAEb;EACpB,CAAC;AACH","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/registration-popup/data/utils.js b/dist/forms/registration-popup/data/utils.js new file mode 100644 index 00000000..929ec28d --- /dev/null +++ b/dist/forms/registration-popup/data/utils.js @@ -0,0 +1,67 @@ +function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } +function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } +function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); } +function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } +import validateEmail from '../../fields/email-field/validator'; +import validateName from '../../fields/name-field/validator'; +import validatePasswordField from '../../fields/password-field/validator'; + +/** + * It accepts complete registration data as payload and checks if the form is valid. + * @param payload + * @param errors + * @param configurableFormFields + * @param fieldDescriptions + * @param formatMessage + * @returns {{fieldErrors, isValid: boolean}} + */ +const isFormValid = (payload, errors, formatMessage) => { + const fieldErrors = _objectSpread({}, errors); + let isValid = true; + let emailSuggestion = { + suggestion: '', + type: '' + }; + Object.keys(payload).forEach(key => { + switch (key) { + case 'name': + fieldErrors.name = validateName(payload.name, formatMessage); + if (fieldErrors.name) { + isValid = false; + } + break; + case 'email': + { + const { + fieldError, + suggestion + } = validateEmail(payload.email, formatMessage); + if (fieldError) { + fieldErrors.email = fieldError; + isValid = false; + } + emailSuggestion = suggestion; + if (fieldErrors.email) { + isValid = false; + } + break; + } + case 'password': + fieldErrors.password = validatePasswordField(payload.password, formatMessage); + if (fieldErrors.password) { + isValid = false; + } + break; + default: + break; + } + }); + return { + isValid, + fieldErrors, + emailSuggestion + }; +}; +export default isFormValid; +//# sourceMappingURL=utils.js.map \ No newline at end of file diff --git a/dist/forms/registration-popup/data/utils.js.map b/dist/forms/registration-popup/data/utils.js.map new file mode 100644 index 00000000..1972b150 --- /dev/null +++ b/dist/forms/registration-popup/data/utils.js.map @@ -0,0 +1 @@ +{"version":3,"file":"utils.js","names":["validateEmail","validateName","validatePasswordField","isFormValid","payload","errors","formatMessage","fieldErrors","_objectSpread","isValid","emailSuggestion","suggestion","type","Object","keys","forEach","key","name","fieldError","email","password"],"sources":["../../../../src/forms/registration-popup/data/utils.js"],"sourcesContent":["import validateEmail from '../../fields/email-field/validator';\nimport validateName from '../../fields/name-field/validator';\nimport validatePasswordField from '../../fields/password-field/validator';\n\n/**\n * It accepts complete registration data as payload and checks if the form is valid.\n * @param payload\n * @param errors\n * @param configurableFormFields\n * @param fieldDescriptions\n * @param formatMessage\n * @returns {{fieldErrors, isValid: boolean}}\n */\nconst isFormValid = (\n payload,\n errors,\n formatMessage,\n) => {\n const fieldErrors = { ...errors };\n let isValid = true;\n let emailSuggestion = { suggestion: '', type: '' };\n\n Object.keys(payload).forEach(key => {\n switch (key) {\n case 'name':\n fieldErrors.name = validateName(payload.name, formatMessage);\n if (fieldErrors.name) { isValid = false; }\n break;\n case 'email': {\n const {\n fieldError, suggestion,\n } = validateEmail(payload.email, formatMessage);\n if (fieldError) {\n fieldErrors.email = fieldError;\n isValid = false;\n }\n emailSuggestion = suggestion;\n if (fieldErrors.email) { isValid = false; }\n break;\n }\n case 'password':\n fieldErrors.password = validatePasswordField(payload.password, formatMessage);\n if (fieldErrors.password) { isValid = false; }\n break;\n default:\n break;\n }\n });\n\n return { isValid, fieldErrors, emailSuggestion };\n};\n\nexport default isFormValid;\n"],"mappings":";;;;;AAAA,OAAOA,aAAa,MAAM,oCAAoC;AAC9D,OAAOC,YAAY,MAAM,mCAAmC;AAC5D,OAAOC,qBAAqB,MAAM,uCAAuC;;AAEzE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,WAAW,GAAGA,CAClBC,OAAO,EACPC,MAAM,EACNC,aAAa,KACV;EACH,MAAMC,WAAW,GAAAC,aAAA,KAAQH,MAAM,CAAE;EACjC,IAAII,OAAO,GAAG,IAAI;EAClB,IAAIC,eAAe,GAAG;IAAEC,UAAU,EAAE,EAAE;IAAEC,IAAI,EAAE;EAAG,CAAC;EAElDC,MAAM,CAACC,IAAI,CAACV,OAAO,CAAC,CAACW,OAAO,CAACC,GAAG,IAAI;IAClC,QAAQA,GAAG;MACX,KAAK,MAAM;QACTT,WAAW,CAACU,IAAI,GAAGhB,YAAY,CAACG,OAAO,CAACa,IAAI,EAAEX,aAAa,CAAC;QAC5D,IAAIC,WAAW,CAACU,IAAI,EAAE;UAAER,OAAO,GAAG,KAAK;QAAE;QACzC;MACF,KAAK,OAAO;QAAE;UACZ,MAAM;YACJS,UAAU;YAAEP;UACd,CAAC,GAAGX,aAAa,CAACI,OAAO,CAACe,KAAK,EAAEb,aAAa,CAAC;UAC/C,IAAIY,UAAU,EAAE;YACdX,WAAW,CAACY,KAAK,GAAGD,UAAU;YAC9BT,OAAO,GAAG,KAAK;UACjB;UACAC,eAAe,GAAGC,UAAU;UAC5B,IAAIJ,WAAW,CAACY,KAAK,EAAE;YAAEV,OAAO,GAAG,KAAK;UAAE;UAC1C;QACF;MACA,KAAK,UAAU;QACbF,WAAW,CAACa,QAAQ,GAAGlB,qBAAqB,CAACE,OAAO,CAACgB,QAAQ,EAAEd,aAAa,CAAC;QAC7E,IAAIC,WAAW,CAACa,QAAQ,EAAE;UAAEX,OAAO,GAAG,KAAK;QAAE;QAC7C;MACF;QACE;IACF;EACF,CAAC,CAAC;EAEF,OAAO;IAAEA,OAAO;IAAEF,WAAW;IAAEG;EAAgB,CAAC;AAClD,CAAC;AAED,eAAeP,WAAW","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/registration-popup/index.js b/dist/forms/registration-popup/index.js new file mode 100644 index 00000000..a74fbb2e --- /dev/null +++ b/dist/forms/registration-popup/index.js @@ -0,0 +1,360 @@ +function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } +function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } +function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); } +function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { getConfig, snakeCaseObject } from '@edx/frontend-platform'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Container, Form, Spinner, StatefulButton } from '@openedx/paragon'; +import HonorCodeAndPrivacyPolicyMessage from './components/honorCodeAndTOS'; +import RegistrationFailureAlert from './components/RegistrationFailureAlert'; +import { clearAllRegistrationErrors, clearRegistrationBackendError, registerUser, setRegistrationFields } from './data/reducers'; +import getBackendValidations from './data/selector'; +import isFormValid from './data/utils'; +import messages from './messages'; +import { setCurrentOpenedForm } from '../../authn-component/data/reducers'; +import { InlineLink, SocialAuthProviders } from '../../common-ui'; +import { COMPLETE_STATE, ENTERPRISE_LOGIN_URL, FAILURE_STATE, FORM_SUBMISSION_ERROR, LOGIN_FORM, REGISTRATION_FORM, TPA_AUTHENTICATION_FAILURE } from '../../data/constants'; +import { useDispatch, useSelector } from '../../data/storeHooks'; +import getAllPossibleQueryParams, { getCountryCookieValue, moveScrollToTop, setCookie } from '../../data/utils'; +import './index.scss'; +import { trackLoginFormToggled, trackRegistrationPageViewed, trackRegistrationSuccess } from '../../tracking/trackers/register'; +import AuthenticatedRedirection from '../common-components/AuthenticatedRedirection'; +import SSOFailureAlert from '../common-components/SSOFailureAlert'; +import ThirdPartyAuthAlert from '../common-components/ThirdPartyAuthAlert'; +import { EmailField, MarketingEmailOptInCheckbox, NameField, PasswordField } from '../fields'; +import useSubjectsList from '../progressive-profiling-popup/data/hooks/useSubjectList'; +import { setSubjectsList } from '../progressive-profiling-popup/data/reducers'; + +/** + * RegisterForm component for handling user registration. + * This component provides a form for users to register with their name, email, password, + * and a checkbox for opting out of marketing emails. + */ +const RegistrationForm = () => { + const { + formatMessage + } = useIntl(); + const dispatch = useDispatch(); + const [formStartTime, setFormStartTime] = useState(null); + const [formFields, setFormFields] = useState({ + name: '', + email: '', + password: '', + marketingEmailsOptIn: true + }); + const [errors, setErrors] = useState({}); + const [errorCode, setErrorCode] = useState({ + type: '', + count: 0 + }); + const [userPipelineDataLoaded, setUserPipelineDataLoaded] = useState(false); + const emailRef = useRef(null); + const registerErrorAlertRef = useRef(null); + const socialAuthnButtonRef = useRef(null); + const registerFormHeadingRef = useRef(null); + const queryParams = useMemo(() => getAllPossibleQueryParams(), []); + const { + subjectsList, + subjectsLoading + } = useSubjectsList(); + const registrationResult = useSelector(state => state.register.registrationResult); + const onboardingComponentContext = useSelector(state => state.commonData.onboardingComponentContext); + const thirdPartyAuthApiStatus = useSelector(state => state.commonData.thirdPartyAuthApiStatus); + const thirdPartyAuthErrorMessage = useSelector(state => state.commonData.thirdPartyAuthContext.errorMessage); + const finishAuthUrl = useSelector(state => state.commonData.thirdPartyAuthContext.finishAuthUrl); + const providers = useSelector(state => state.commonData.thirdPartyAuthContext?.providers); + const currentProvider = useSelector(state => state.commonData.thirdPartyAuthContext.currentProvider); + const pipelineUserDetails = useSelector(state => state.commonData.thirdPartyAuthContext.pipelineUserDetails); + const authContextCountryCode = useSelector(state => state.commonData.thirdPartyAuthContext.countryCode); + const registrationError = useSelector(state => state.register.registrationError); + const isLoginSSOIntent = useSelector(state => state.login.isLoginSSOIntent); + const registrationErrorCode = registrationError?.errorCode; + const backendValidations = useSelector(getBackendValidations); + const submitState = useSelector(state => state.register.submitState); + const autoSubmitRegForm = currentProvider && thirdPartyAuthApiStatus === COMPLETE_STATE && !isLoginSSOIntent && queryParams?.authMode === 'Register' && !localStorage.getItem('ssoPipelineRedirectionDone'); + + /** + * Set the userPipelineDetails data in formFields for only first time + */ + useEffect(() => { + if (!userPipelineDataLoaded && thirdPartyAuthApiStatus === COMPLETE_STATE) { + if (thirdPartyAuthErrorMessage) { + setErrorCode(prevState => ({ + type: TPA_AUTHENTICATION_FAILURE, + count: prevState.count + 1 + })); + localStorage.removeItem('marketingEmailsOptIn'); + localStorage.removeItem('ssoPipelineRedirectionDone'); + } + if (pipelineUserDetails && Object.keys(pipelineUserDetails).length !== 0) { + const { + name = '', + email = '' + } = pipelineUserDetails; + setFormFields(prevState => _objectSpread(_objectSpread({}, prevState), {}, { + name, + email + })); + setUserPipelineDataLoaded(true); + } + } + }, [ + // eslint-disable-line react-hooks/exhaustive-deps + thirdPartyAuthApiStatus, thirdPartyAuthErrorMessage, pipelineUserDetails, userPipelineDataLoaded]); + useEffect(() => { + if (thirdPartyAuthApiStatus === COMPLETE_STATE) { + if (providers.length > 0 && socialAuthnButtonRef.current) { + socialAuthnButtonRef.current.focus(); + } else if (emailRef.current) { + emailRef.current.focus(); + } + } else if (thirdPartyAuthApiStatus === FAILURE_STATE) { + emailRef.current.focus(); + } + }, [thirdPartyAuthApiStatus, providers]); + useEffect(() => { + moveScrollToTop(registerFormHeadingRef, 'end'); + }, []); + useEffect(() => { + if (!subjectsLoading) { + dispatch(setSubjectsList(subjectsList)); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [dispatch, subjectsLoading]); + const handleOnChange = event => { + const { + name + } = event.target; + const value = event.target.type === 'checkbox' ? event.target.checked : event.target.value; + if (registrationError[name]) { + dispatch(clearRegistrationBackendError(name)); + } + // seting marketingEmailsOptIn state for SSO authentication flow for register API call + if (name === 'marketingEmailsOptIn') { + dispatch(setRegistrationFields({ + [name]: value + })); + } + setErrors(prevErrors => _objectSpread(_objectSpread({}, prevErrors), {}, { + [name]: '' + })); + setFormFields(prevState => _objectSpread(_objectSpread({}, prevState), {}, { + [name]: value + })); + }; + useEffect(() => { + if (thirdPartyAuthApiStatus === COMPLETE_STATE && currentProvider === null && localStorage.getItem('ssoPipelineRedirectionDone')) { + localStorage.removeItem('ssoPipelineRedirectionDone'); + localStorage.removeItem('marketingEmailsOptIn'); + } + }, [currentProvider, thirdPartyAuthApiStatus]); + useEffect(() => { + if (registrationResult.success) { + // clear local storage + localStorage.removeItem('marketingEmailsOptIn'); + localStorage.removeItem('ssoPipelineRedirectionDone'); + + // This event is used by GTM + trackRegistrationSuccess(); + + // This is used by the "User Retention Rate Event" on GTM + setCookie(getConfig().USER_RETENTION_COOKIE_NAME, true); + } + }, [registrationResult]); + useEffect(() => { + if (!formStartTime) { + trackRegistrationPageViewed(); + setFormStartTime(Date.now()); + } + }, [formStartTime]); + useEffect(() => { + if (backendValidations) { + setErrors(prevErrors => _objectSpread(_objectSpread({}, prevErrors), backendValidations)); + } + }, [backendValidations]); + useEffect(() => { + if (registrationErrorCode) { + setErrorCode(prevState => ({ + type: registrationErrorCode, + count: prevState.count + 1 + })); + moveScrollToTop(registerErrorAlertRef); + if (registerErrorAlertRef.current) { + registerErrorAlertRef.current.focus(); + } + } + }, [registrationErrorCode]); + const handleErrorChange = (fieldName, error) => { + setErrors(prevErrors => _objectSpread(_objectSpread({}, prevErrors), {}, { + [fieldName]: error + })); + }; + const handleUserRegistration = () => { + const totalRegistrationTime = (Date.now() - formStartTime) / 1000; + const userCountryCode = getCountryCookieValue(); + let payload = _objectSpread(_objectSpread({}, formFields), {}, { + honor_code: true, + terms_of_service: true, + app_name: 'onboarding_component' + }); + if (currentProvider) { + delete payload.password; + payload.social_auth_provider = currentProvider; + if (!isLoginSSOIntent) { + delete payload.marketingEmailsOptIn; + payload.marketingEmailsOptIn = localStorage.getItem('marketingEmailsOptIn'); + } + } + + // add country in payload if country cookie value or mfe_context country exists + if (userCountryCode) { + payload.country = userCountryCode; + } else if (authContextCountryCode) { + payload.country = authContextCountryCode; + } + + // Validating form data before submitting + const { + isValid, + fieldErrors + } = isFormValid(payload, errors, formatMessage); + setErrors(_objectSpread({}, fieldErrors)); + if (!isValid) { + setErrorCode(prevState => ({ + type: FORM_SUBMISSION_ERROR, + count: prevState.count + 1 + })); + moveScrollToTop(registerErrorAlertRef); + return; + } + payload = _objectSpread(_objectSpread(_objectSpread({}, onboardingComponentContext), queryParams), payload); + payload = snakeCaseObject(payload); + payload.totalRegistrationTime = totalRegistrationTime; + dispatch(registerUser(payload)); + }; + const handleSubmit = e => { + e.preventDefault(); + handleUserRegistration(); + }; + useEffect(() => { + if (autoSubmitRegForm && userPipelineDataLoaded) { + handleUserRegistration(); + } + }, [autoSubmitRegForm, userPipelineDataLoaded]); // eslint-disable-line react-hooks/exhaustive-deps + + return /*#__PURE__*/React.createElement("div", { + className: "flex-column" + }, /*#__PURE__*/React.createElement(Container, { + size: "lg", + className: "authn__popup-container" + }, /*#__PURE__*/React.createElement(AuthenticatedRedirection, { + success: registrationResult.success, + redirectUrl: registrationResult.redirectUrl, + finishAuthUrl: finishAuthUrl, + redirectToProgressiveProfilingForm: true + }), /*#__PURE__*/React.createElement("h2", { + className: "font-italic text-center display-1 mb-0", + "data-testid": "sign-up-heading", + ref: registerFormHeadingRef + }, formatMessage(messages.registrationFormHeading1)), /*#__PURE__*/React.createElement("hr", { + className: "separator my-3 my-sm-4" + }), /*#__PURE__*/React.createElement(SSOFailureAlert, { + errorCode: errorCode.type, + context: { + errorMessage: thirdPartyAuthErrorMessage + } + }), autoSubmitRegForm && !errorCode.type ? /*#__PURE__*/React.createElement("div", { + className: "my-6 text-center" + }, /*#__PURE__*/React.createElement(Spinner, { + animation: "border", + variant: "primary", + id: "tpa-spinner" + })) : /*#__PURE__*/React.createElement(React.Fragment, null, (!autoSubmitRegForm || errorCode.type) && !currentProvider && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(SocialAuthProviders, { + isLoginForm: false, + ref: socialAuthnButtonRef + }), /*#__PURE__*/React.createElement("div", { + className: "text-center mb-4 mt-3" + }, formatMessage(messages.registrationFormHeading2))), /*#__PURE__*/React.createElement(ThirdPartyAuthAlert, { + currentProvider: currentProvider, + referrer: REGISTRATION_FORM + }), /*#__PURE__*/React.createElement("div", { + ref: registerErrorAlertRef, + tabIndex: "-1", + "aria-live": "assertive" + }, /*#__PURE__*/React.createElement(RegistrationFailureAlert, { + errorCode: errorCode.type, + failureCount: errorCode.count, + context: { + provider: currentProvider, + errorMessage: thirdPartyAuthErrorMessage + } + })), /*#__PURE__*/React.createElement(Form, { + id: "registration-form", + name: "registration-form", + className: "d-flex flex-column my-4" + }, /*#__PURE__*/React.createElement(EmailField, { + name: "email", + value: formFields.email, + errorMessage: errors.email, + handleChange: handleOnChange, + handleErrorChange: handleErrorChange, + floatingLabel: formatMessage(messages.registrationFormEmailFieldLabel), + ref: emailRef + }), /*#__PURE__*/React.createElement(NameField, { + label: "Full name", + name: "name", + value: formFields.name, + errorMessage: errors.name, + handleChange: handleOnChange, + handleErrorChange: handleErrorChange, + handleFocus: () => {} + }), !currentProvider && /*#__PURE__*/React.createElement(PasswordField, { + name: "password", + value: formFields.password, + errorMessage: errors.password, + handleChange: handleOnChange, + handleErrorChange: handleErrorChange, + handleFocus: () => {}, + floatingLabel: formatMessage(messages.registrationFormPasswordFieldLabel) + }), /*#__PURE__*/React.createElement(MarketingEmailOptInCheckbox, { + name: "marketingEmailsOptIn", + value: formFields.marketingEmailsOptIn, + handleChange: handleOnChange + }), /*#__PURE__*/React.createElement("div", { + className: "d-flex flex-column my-4" + }, /*#__PURE__*/React.createElement(StatefulButton, { + id: "register-user", + name: "register-user", + type: "submit", + variant: "primary", + className: "align-self-end registration-form__submit-btn__width authn-btn__pill-shaped", + state: submitState, + labels: { + default: formatMessage(messages.registrationFormCreateAccountButton), + pending: '' + }, + onClick: handleSubmit, + onMouseDown: e => e.preventDefault() + }))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(InlineLink, { + className: "mb-2", + onClick: () => { + trackLoginFormToggled(); + dispatch(clearAllRegistrationErrors()); + dispatch(setCurrentOpenedForm(LOGIN_FORM)); + }, + linkHelpText: formatMessage(messages.registrationFormAlreadyHaveAccountText), + linkText: formatMessage(messages.registrationFormSignInLink) + }), /*#__PURE__*/React.createElement(InlineLink, { + destination: getConfig().LMS_BASE_URL + ENTERPRISE_LOGIN_URL, + linkHelpText: formatMessage(messages.registrationFormSchoolOrOrganizationLink), + linkText: formatMessage(messages.registrationFormSignInWithCredentialsLink) + })))), !(autoSubmitRegForm && !errorCode.type) && /*#__PURE__*/React.createElement("div", { + className: "bg-dark-500" + }, /*#__PURE__*/React.createElement("p", { + className: "mb-0 text-white m-auto authn-popup__registration-footer" + }, /*#__PURE__*/React.createElement(HonorCodeAndPrivacyPolicyMessage, null)))); +}; +export default RegistrationForm; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/forms/registration-popup/index.js.map b/dist/forms/registration-popup/index.js.map new file mode 100644 index 00000000..af5601bc --- /dev/null +++ b/dist/forms/registration-popup/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["React","useEffect","useMemo","useRef","useState","getConfig","snakeCaseObject","useIntl","Container","Form","Spinner","StatefulButton","HonorCodeAndPrivacyPolicyMessage","RegistrationFailureAlert","clearAllRegistrationErrors","clearRegistrationBackendError","registerUser","setRegistrationFields","getBackendValidations","isFormValid","messages","setCurrentOpenedForm","InlineLink","SocialAuthProviders","COMPLETE_STATE","ENTERPRISE_LOGIN_URL","FAILURE_STATE","FORM_SUBMISSION_ERROR","LOGIN_FORM","REGISTRATION_FORM","TPA_AUTHENTICATION_FAILURE","useDispatch","useSelector","getAllPossibleQueryParams","getCountryCookieValue","moveScrollToTop","setCookie","trackLoginFormToggled","trackRegistrationPageViewed","trackRegistrationSuccess","AuthenticatedRedirection","SSOFailureAlert","ThirdPartyAuthAlert","EmailField","MarketingEmailOptInCheckbox","NameField","PasswordField","useSubjectsList","setSubjectsList","RegistrationForm","formatMessage","dispatch","formStartTime","setFormStartTime","formFields","setFormFields","name","email","password","marketingEmailsOptIn","errors","setErrors","errorCode","setErrorCode","type","count","userPipelineDataLoaded","setUserPipelineDataLoaded","emailRef","registerErrorAlertRef","socialAuthnButtonRef","registerFormHeadingRef","queryParams","subjectsList","subjectsLoading","registrationResult","state","register","onboardingComponentContext","commonData","thirdPartyAuthApiStatus","thirdPartyAuthErrorMessage","thirdPartyAuthContext","errorMessage","finishAuthUrl","providers","currentProvider","pipelineUserDetails","authContextCountryCode","countryCode","registrationError","isLoginSSOIntent","login","registrationErrorCode","backendValidations","submitState","autoSubmitRegForm","authMode","localStorage","getItem","prevState","removeItem","Object","keys","length","_objectSpread","current","focus","handleOnChange","event","target","value","checked","prevErrors","success","USER_RETENTION_COOKIE_NAME","Date","now","handleErrorChange","fieldName","error","handleUserRegistration","totalRegistrationTime","userCountryCode","payload","honor_code","terms_of_service","app_name","social_auth_provider","country","isValid","fieldErrors","handleSubmit","e","preventDefault","createElement","className","size","redirectUrl","redirectToProgressiveProfilingForm","ref","registrationFormHeading1","context","animation","variant","id","Fragment","isLoginForm","registrationFormHeading2","referrer","tabIndex","failureCount","provider","handleChange","floatingLabel","registrationFormEmailFieldLabel","label","handleFocus","registrationFormPasswordFieldLabel","labels","default","registrationFormCreateAccountButton","pending","onClick","onMouseDown","linkHelpText","registrationFormAlreadyHaveAccountText","linkText","registrationFormSignInLink","destination","LMS_BASE_URL","registrationFormSchoolOrOrganizationLink","registrationFormSignInWithCredentialsLink"],"sources":["../../../src/forms/registration-popup/index.jsx"],"sourcesContent":["import React, {\n useEffect, useMemo, useRef, useState,\n} from 'react';\n\nimport { getConfig, snakeCaseObject } from '@edx/frontend-platform';\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport {\n Container, Form, Spinner, StatefulButton,\n} from '@openedx/paragon';\n\nimport HonorCodeAndPrivacyPolicyMessage from './components/honorCodeAndTOS';\nimport RegistrationFailureAlert from './components/RegistrationFailureAlert';\nimport {\n clearAllRegistrationErrors,\n clearRegistrationBackendError,\n registerUser,\n setRegistrationFields,\n} from './data/reducers';\nimport getBackendValidations from './data/selector';\nimport isFormValid from './data/utils';\nimport messages from './messages';\nimport { setCurrentOpenedForm } from '../../authn-component/data/reducers';\nimport { InlineLink, SocialAuthProviders } from '../../common-ui';\nimport {\n COMPLETE_STATE,\n ENTERPRISE_LOGIN_URL,\n FAILURE_STATE,\n FORM_SUBMISSION_ERROR,\n LOGIN_FORM,\n REGISTRATION_FORM,\n TPA_AUTHENTICATION_FAILURE,\n} from '../../data/constants';\nimport { useDispatch, useSelector } from '../../data/storeHooks';\nimport getAllPossibleQueryParams, { getCountryCookieValue, moveScrollToTop, setCookie } from '../../data/utils';\nimport './index.scss';\nimport {\n trackLoginFormToggled,\n trackRegistrationPageViewed,\n trackRegistrationSuccess,\n} from '../../tracking/trackers/register';\nimport AuthenticatedRedirection from '../common-components/AuthenticatedRedirection';\nimport SSOFailureAlert from '../common-components/SSOFailureAlert';\nimport ThirdPartyAuthAlert from '../common-components/ThirdPartyAuthAlert';\nimport {\n EmailField,\n MarketingEmailOptInCheckbox,\n NameField,\n PasswordField,\n} from '../fields';\nimport useSubjectsList from '../progressive-profiling-popup/data/hooks/useSubjectList';\nimport { setSubjectsList } from '../progressive-profiling-popup/data/reducers';\n\n/**\n * RegisterForm component for handling user registration.\n * This component provides a form for users to register with their name, email, password,\n * and a checkbox for opting out of marketing emails.\n */\nconst RegistrationForm = () => {\n const { formatMessage } = useIntl();\n const dispatch = useDispatch();\n const [formStartTime, setFormStartTime] = useState(null);\n\n const [formFields, setFormFields] = useState({\n name: '', email: '', password: '', marketingEmailsOptIn: true,\n });\n const [errors, setErrors] = useState({});\n const [errorCode, setErrorCode] = useState({ type: '', count: 0 });\n const [userPipelineDataLoaded, setUserPipelineDataLoaded] = useState(false);\n\n const emailRef = useRef(null);\n const registerErrorAlertRef = useRef(null);\n const socialAuthnButtonRef = useRef(null);\n const registerFormHeadingRef = useRef(null);\n const queryParams = useMemo(() => getAllPossibleQueryParams(), []);\n const { subjectsList, subjectsLoading } = useSubjectsList();\n\n const registrationResult = useSelector(state => state.register.registrationResult);\n\n const onboardingComponentContext = useSelector(state => state.commonData.onboardingComponentContext);\n const thirdPartyAuthApiStatus = useSelector(state => state.commonData.thirdPartyAuthApiStatus);\n const thirdPartyAuthErrorMessage = useSelector(state => state.commonData.thirdPartyAuthContext.errorMessage);\n const finishAuthUrl = useSelector(state => state.commonData.thirdPartyAuthContext.finishAuthUrl);\n const providers = useSelector(state => state.commonData.thirdPartyAuthContext?.providers);\n const currentProvider = useSelector(state => state.commonData.thirdPartyAuthContext.currentProvider);\n const pipelineUserDetails = useSelector(state => state.commonData.thirdPartyAuthContext.pipelineUserDetails);\n const authContextCountryCode = useSelector(state => state.commonData.thirdPartyAuthContext.countryCode);\n const registrationError = useSelector(state => state.register.registrationError);\n const isLoginSSOIntent = useSelector(state => state.login.isLoginSSOIntent);\n const registrationErrorCode = registrationError?.errorCode;\n const backendValidations = useSelector(getBackendValidations);\n const submitState = useSelector(state => state.register.submitState);\n\n const autoSubmitRegForm = (currentProvider\n && thirdPartyAuthApiStatus === COMPLETE_STATE\n && !isLoginSSOIntent\n && queryParams?.authMode === 'Register'\n && !localStorage.getItem('ssoPipelineRedirectionDone')\n );\n\n /**\n * Set the userPipelineDetails data in formFields for only first time\n */\n useEffect(() => {\n if (!userPipelineDataLoaded && thirdPartyAuthApiStatus === COMPLETE_STATE) {\n if (thirdPartyAuthErrorMessage) {\n setErrorCode(prevState => ({ type: TPA_AUTHENTICATION_FAILURE, count: prevState.count + 1 }));\n localStorage.removeItem('marketingEmailsOptIn');\n localStorage.removeItem('ssoPipelineRedirectionDone');\n }\n if (pipelineUserDetails && Object.keys(pipelineUserDetails).length !== 0) {\n const {\n name = '', email = '',\n } = pipelineUserDetails;\n setFormFields(prevState => ({\n ...prevState, name, email,\n }));\n setUserPipelineDataLoaded(true);\n }\n }\n }, [ // eslint-disable-line react-hooks/exhaustive-deps\n thirdPartyAuthApiStatus,\n thirdPartyAuthErrorMessage,\n pipelineUserDetails,\n userPipelineDataLoaded,\n ]);\n\n useEffect(() => {\n if (thirdPartyAuthApiStatus === COMPLETE_STATE) {\n if (providers.length > 0 && socialAuthnButtonRef.current) {\n socialAuthnButtonRef.current.focus();\n } else if (emailRef.current) {\n emailRef.current.focus();\n }\n } else if (thirdPartyAuthApiStatus === FAILURE_STATE) {\n emailRef.current.focus();\n }\n }, [thirdPartyAuthApiStatus, providers]);\n\n useEffect(() => {\n moveScrollToTop(registerFormHeadingRef, 'end');\n }, []);\n\n useEffect(() => {\n if (!subjectsLoading) {\n dispatch(setSubjectsList(subjectsList));\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [dispatch, subjectsLoading]);\n\n const handleOnChange = (event) => {\n const { name } = event.target;\n const value = event.target.type === 'checkbox' ? event.target.checked : event.target.value;\n\n if (registrationError[name]) {\n dispatch(clearRegistrationBackendError(name));\n }\n // seting marketingEmailsOptIn state for SSO authentication flow for register API call\n if (name === 'marketingEmailsOptIn') {\n dispatch(setRegistrationFields({ [name]: value }));\n }\n setErrors(prevErrors => ({ ...prevErrors, [name]: '' }));\n setFormFields(prevState => ({ ...prevState, [name]: value }));\n };\n\n useEffect(() => {\n if (thirdPartyAuthApiStatus === COMPLETE_STATE\n && currentProvider === null\n && localStorage.getItem('ssoPipelineRedirectionDone')\n ) {\n localStorage.removeItem('ssoPipelineRedirectionDone');\n localStorage.removeItem('marketingEmailsOptIn');\n }\n }, [currentProvider, thirdPartyAuthApiStatus]);\n\n useEffect(() => {\n if (registrationResult.success) {\n // clear local storage\n localStorage.removeItem('marketingEmailsOptIn');\n localStorage.removeItem('ssoPipelineRedirectionDone');\n\n // This event is used by GTM\n trackRegistrationSuccess();\n\n // This is used by the \"User Retention Rate Event\" on GTM\n setCookie(getConfig().USER_RETENTION_COOKIE_NAME, true);\n }\n }, [registrationResult]);\n\n useEffect(() => {\n if (!formStartTime) {\n trackRegistrationPageViewed();\n setFormStartTime(Date.now());\n }\n }, [formStartTime]);\n\n useEffect(() => {\n if (backendValidations) {\n setErrors(prevErrors => ({ ...prevErrors, ...backendValidations }));\n }\n }, [backendValidations]);\n\n useEffect(() => {\n if (registrationErrorCode) {\n setErrorCode(prevState => ({ type: registrationErrorCode, count: prevState.count + 1 }));\n moveScrollToTop(registerErrorAlertRef);\n if (registerErrorAlertRef.current) {\n registerErrorAlertRef.current.focus();\n }\n }\n }, [registrationErrorCode]);\n\n const handleErrorChange = (fieldName, error) => {\n setErrors(prevErrors => ({\n ...prevErrors,\n [fieldName]: error,\n }));\n };\n\n const handleUserRegistration = () => {\n const totalRegistrationTime = (Date.now() - formStartTime) / 1000;\n const userCountryCode = getCountryCookieValue();\n let payload = {\n ...formFields, honor_code: true, terms_of_service: true, app_name: 'onboarding_component',\n };\n\n if (currentProvider) {\n delete payload.password;\n payload.social_auth_provider = currentProvider;\n\n if (!isLoginSSOIntent) {\n delete payload.marketingEmailsOptIn;\n payload.marketingEmailsOptIn = localStorage.getItem('marketingEmailsOptIn');\n }\n }\n\n // add country in payload if country cookie value or mfe_context country exists\n if (userCountryCode) {\n payload.country = userCountryCode;\n } else if (authContextCountryCode) {\n payload.country = authContextCountryCode;\n }\n\n // Validating form data before submitting\n const { isValid, fieldErrors } = isFormValid(\n payload,\n errors,\n formatMessage,\n );\n setErrors({ ...fieldErrors });\n\n if (!isValid) {\n setErrorCode(prevState => ({ type: FORM_SUBMISSION_ERROR, count: prevState.count + 1 }));\n moveScrollToTop(registerErrorAlertRef);\n return;\n }\n\n payload = {\n ...onboardingComponentContext, ...queryParams, ...payload,\n };\n payload = snakeCaseObject(payload);\n payload.totalRegistrationTime = totalRegistrationTime;\n dispatch(registerUser(payload));\n };\n\n const handleSubmit = (e) => {\n e.preventDefault();\n handleUserRegistration();\n };\n\n useEffect(() => {\n if (autoSubmitRegForm && userPipelineDataLoaded) {\n handleUserRegistration();\n }\n }, [autoSubmitRegForm, userPipelineDataLoaded]); // eslint-disable-line react-hooks/exhaustive-deps\n\n return (\n
\n \n \n \n {formatMessage(messages.registrationFormHeading1)}\n \n
\n\n \n\n {(autoSubmitRegForm && !errorCode.type) ? (\n
\n \n
\n ) : (\n <>\n {(!autoSubmitRegForm || errorCode.type) && (!currentProvider) && (\n <>\n \n
\n {formatMessage(messages.registrationFormHeading2)}\n
\n \n )}\n\n \n
\n \n
\n
\n \n { }}\n />\n {!currentProvider && (\n { }}\n floatingLabel={formatMessage(messages.registrationFormPasswordFieldLabel)}\n />\n )}\n \n
\n e.preventDefault()}\n />\n\n
\n \n
\n {\n trackLoginFormToggled();\n dispatch(clearAllRegistrationErrors());\n dispatch(setCurrentOpenedForm(LOGIN_FORM));\n }}\n linkHelpText={formatMessage(messages.registrationFormAlreadyHaveAccountText)}\n linkText={formatMessage(messages.registrationFormSignInLink)}\n />\n \n
\n \n )}\n
\n {!(autoSubmitRegForm && !errorCode.type) && (\n
\n

\n \n

\n
\n )}\n
\n );\n};\n\nexport default RegistrationForm;\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/registration-popup/index.scss b/dist/forms/registration-popup/index.scss new file mode 100644 index 00000000..ffd66770 --- /dev/null +++ b/dist/forms/registration-popup/index.scss @@ -0,0 +1,13 @@ +@import "~@edx/brand-edx.org/paragon/variables"; + +.registration-form .back-button-container { + padding: 0.5rem 1.25rem !important; +} + +.registration-form__tos-and-privacy-policy__link { + text-decoration-color: $white !important; +} + +.registration-form__submit-btn__width { + min-width: 15rem !important; +} diff --git a/dist/forms/registration-popup/messages.js b/dist/forms/registration-popup/messages.js new file mode 100644 index 00000000..6b39d6cc --- /dev/null +++ b/dist/forms/registration-popup/messages.js @@ -0,0 +1,102 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; +const messages = defineMessages({ + registrationFormHeading1: { + id: 'registration.form.heading.1', + defaultMessage: 'Create account', + description: 'registration form main heading' + }, + registrationFormHeading2: { + id: 'registration.form.or.heading.2', + defaultMessage: 'or', + description: 'Heading that appears between social auth and basic registration form' + }, + registrationFormCreateAccountButton: { + id: 'registration.form.continue.button', + defaultMessage: 'Create an account for free', + description: 'Text for submit button on registration form' + }, + registrationFormAlreadyHaveAccountText: { + id: 'registration.form.already.have.account.text', + defaultMessage: 'Already have an account?', + description: 'Login button help text' + }, + registrationFormSignInLink: { + id: 'registration.form.sign.in.link', + defaultMessage: 'Sign In', + description: 'Text for sign in link' + }, + registrationFormSchoolOrOrganizationLink: { + id: 'registration.form.account.school.organization.text', + defaultMessage: 'Have an account through school or organization?', + description: 'Label for link that leads learners to the institution login page' + }, + registrationFormSignInWithCredentialsLink: { + id: 'registration.form.sign.in.with.credentials.link', + defaultMessage: 'Sign in with your credentials', + description: 'Text for signing in with credentials' + }, + registrationFormPasswordFieldLabel: { + id: 'registration.form.password.label', + defaultMessage: 'Password', + description: 'Label for password input field' + }, + registrationFormEmailFieldLabel: { + id: 'registration.form.email.label', + defaultMessage: 'Email', + description: 'Label for email input field' + }, + registrationFormTermsOfServiceAndHonorCodeLabel: { + id: 'registration.form.terms.of.service.and.honor.code.label', + defaultMessage: 'Terms of Service and Honor Code', + description: 'Label for terms of service and honor code link' + }, + registrationFormPrivacyPolicyLabel: { + id: 'registration.form.privacy.policy.label', + defaultMessage: 'Privacy Policy', + description: 'Label for edX privacy policy link' + }, + // error messages + registrationFailureHeaderTitle: { + id: 'register.failure.header.title', + defaultMessage: 'We couldn\'t create your account.', + description: 'Login failure header message.' + }, + // Error messages + registrationEmptyFormSubmissionError: { + id: 'registration.empty.form.submission.error', + defaultMessage: 'Please check your responses and try again.', + description: 'Error message that appears on top of the form when empty form is submitted' + }, + registrationRequestServerError: { + id: 'registration.request.server.error', + defaultMessage: 'An error has occurred. Try refreshing the page, or check your internet connection.', + description: 'Error message for internal server error.' + }, + registrationRateLimitError: { + id: 'registration.rate.limit.error', + defaultMessage: 'Too many failed registration attempts. Try again later.', + description: 'Error message that appears when an anonymous user has made too many failed registration attempts' + }, + registrationTPASessionExpired: { + id: 'registration.tpa.session.expired', + defaultMessage: 'We couldn’t create your account. Registration using {provider} has timed out.', + description: '' + }, + internalServerErrorMessage: { + id: 'internal.server.error.message', + defaultMessage: 'An error has occurred. Try refreshing the page, or check your internet connection.', + description: 'Error message that appears when server responds with 500 error code' + }, + registrationTPAAuthenticationFailure: { + id: 'registration.tpa.authentication.failure', + defaultMessage: 'We are sorry, you are not authorized to access {platform_name} via this channel. ' + 'Please contact your learning administrator or manager in order to access {platform_name}.' + '{lineBreak}{lineBreak}Error Details:{lineBreak}{errorMessage}', + description: 'Error message third party authentication pipeline fails' + }, + registrationFormSubmissionError: { + id: 'registration.form.submission.error', + defaultMessage: 'We couldn’t create your account. Please correct the errors below.', + description: 'Error message that appears when form submit with errors' + } +}); +export default messages; +//# sourceMappingURL=messages.js.map \ No newline at end of file diff --git a/dist/forms/registration-popup/messages.js.map b/dist/forms/registration-popup/messages.js.map new file mode 100644 index 00000000..24d3eb9b --- /dev/null +++ b/dist/forms/registration-popup/messages.js.map @@ -0,0 +1 @@ +{"version":3,"file":"messages.js","names":["defineMessages","messages","registrationFormHeading1","id","defaultMessage","description","registrationFormHeading2","registrationFormCreateAccountButton","registrationFormAlreadyHaveAccountText","registrationFormSignInLink","registrationFormSchoolOrOrganizationLink","registrationFormSignInWithCredentialsLink","registrationFormPasswordFieldLabel","registrationFormEmailFieldLabel","registrationFormTermsOfServiceAndHonorCodeLabel","registrationFormPrivacyPolicyLabel","registrationFailureHeaderTitle","registrationEmptyFormSubmissionError","registrationRequestServerError","registrationRateLimitError","registrationTPASessionExpired","internalServerErrorMessage","registrationTPAAuthenticationFailure","registrationFormSubmissionError"],"sources":["../../../src/forms/registration-popup/messages.jsx"],"sourcesContent":["import { defineMessages } from '@edx/frontend-platform/i18n';\n\nconst messages = defineMessages({\n registrationFormHeading1: {\n id: 'registration.form.heading.1',\n defaultMessage: 'Create account',\n description: 'registration form main heading',\n },\n registrationFormHeading2: {\n id: 'registration.form.or.heading.2',\n defaultMessage: 'or',\n description: 'Heading that appears between social auth and basic registration form',\n },\n registrationFormCreateAccountButton: {\n id: 'registration.form.continue.button',\n defaultMessage: 'Create an account for free',\n description: 'Text for submit button on registration form',\n },\n registrationFormAlreadyHaveAccountText: {\n id: 'registration.form.already.have.account.text',\n defaultMessage: 'Already have an account?',\n description: 'Login button help text',\n },\n registrationFormSignInLink: {\n id: 'registration.form.sign.in.link',\n defaultMessage: 'Sign In',\n description: 'Text for sign in link',\n },\n registrationFormSchoolOrOrganizationLink: {\n id: 'registration.form.account.school.organization.text',\n defaultMessage: 'Have an account through school or organization?',\n description: 'Label for link that leads learners to the institution login page',\n },\n registrationFormSignInWithCredentialsLink: {\n id: 'registration.form.sign.in.with.credentials.link',\n defaultMessage: 'Sign in with your credentials',\n description: 'Text for signing in with credentials',\n },\n registrationFormPasswordFieldLabel: {\n id: 'registration.form.password.label',\n defaultMessage: 'Password',\n description: 'Label for password input field',\n },\n registrationFormEmailFieldLabel: {\n id: 'registration.form.email.label',\n defaultMessage: 'Email',\n description: 'Label for email input field',\n },\n registrationFormTermsOfServiceAndHonorCodeLabel: {\n id: 'registration.form.terms.of.service.and.honor.code.label',\n defaultMessage: 'Terms of Service and Honor Code',\n description: 'Label for terms of service and honor code link',\n },\n registrationFormPrivacyPolicyLabel: {\n id: 'registration.form.privacy.policy.label',\n defaultMessage: 'Privacy Policy',\n description: 'Label for edX privacy policy link',\n },\n // error messages\n registrationFailureHeaderTitle: {\n id: 'register.failure.header.title',\n defaultMessage: 'We couldn\\'t create your account.',\n description: 'Login failure header message.',\n },\n // Error messages\n registrationEmptyFormSubmissionError: {\n id: 'registration.empty.form.submission.error',\n defaultMessage: 'Please check your responses and try again.',\n description: 'Error message that appears on top of the form when empty form is submitted',\n },\n registrationRequestServerError: {\n id: 'registration.request.server.error',\n defaultMessage: 'An error has occurred. Try refreshing the page, or check your internet connection.',\n description: 'Error message for internal server error.',\n },\n registrationRateLimitError: {\n id: 'registration.rate.limit.error',\n defaultMessage: 'Too many failed registration attempts. Try again later.',\n description: 'Error message that appears when an anonymous user has made too many failed registration attempts',\n },\n registrationTPASessionExpired: {\n id: 'registration.tpa.session.expired',\n defaultMessage: 'We couldn’t create your account. Registration using {provider} has timed out.',\n description: '',\n },\n internalServerErrorMessage: {\n id: 'internal.server.error.message',\n defaultMessage: 'An error has occurred. Try refreshing the page, or check your internet connection.',\n description: 'Error message that appears when server responds with 500 error code',\n },\n registrationTPAAuthenticationFailure: {\n id: 'registration.tpa.authentication.failure',\n defaultMessage: 'We are sorry, you are not authorized to access {platform_name} via this channel. '\n + 'Please contact your learning administrator or manager in order to access {platform_name}.'\n + '{lineBreak}{lineBreak}Error Details:{lineBreak}{errorMessage}',\n description: 'Error message third party authentication pipeline fails',\n },\n registrationFormSubmissionError: {\n id: 'registration.form.submission.error',\n defaultMessage: 'We couldn’t create your account. Please correct the errors below.',\n description: 'Error message that appears when form submit with errors',\n },\n});\n\nexport default messages;\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,6BAA6B;AAE5D,MAAMC,QAAQ,GAAGD,cAAc,CAAC;EAC9BE,wBAAwB,EAAE;IACxBC,EAAE,EAAE,6BAA6B;IACjCC,cAAc,EAAE,gBAAgB;IAChCC,WAAW,EAAE;EACf,CAAC;EACDC,wBAAwB,EAAE;IACxBH,EAAE,EAAE,gCAAgC;IACpCC,cAAc,EAAE,IAAI;IACpBC,WAAW,EAAE;EACf,CAAC;EACDE,mCAAmC,EAAE;IACnCJ,EAAE,EAAE,mCAAmC;IACvCC,cAAc,EAAE,4BAA4B;IAC5CC,WAAW,EAAE;EACf,CAAC;EACDG,sCAAsC,EAAE;IACtCL,EAAE,EAAE,6CAA6C;IACjDC,cAAc,EAAE,0BAA0B;IAC1CC,WAAW,EAAE;EACf,CAAC;EACDI,0BAA0B,EAAE;IAC1BN,EAAE,EAAE,gCAAgC;IACpCC,cAAc,EAAE,SAAS;IACzBC,WAAW,EAAE;EACf,CAAC;EACDK,wCAAwC,EAAE;IACxCP,EAAE,EAAE,oDAAoD;IACxDC,cAAc,EAAE,iDAAiD;IACjEC,WAAW,EAAE;EACf,CAAC;EACDM,yCAAyC,EAAE;IACzCR,EAAE,EAAE,iDAAiD;IACrDC,cAAc,EAAE,+BAA+B;IAC/CC,WAAW,EAAE;EACf,CAAC;EACDO,kCAAkC,EAAE;IAClCT,EAAE,EAAE,kCAAkC;IACtCC,cAAc,EAAE,UAAU;IAC1BC,WAAW,EAAE;EACf,CAAC;EACDQ,+BAA+B,EAAE;IAC/BV,EAAE,EAAE,+BAA+B;IACnCC,cAAc,EAAE,OAAO;IACvBC,WAAW,EAAE;EACf,CAAC;EACDS,+CAA+C,EAAE;IAC/CX,EAAE,EAAE,yDAAyD;IAC7DC,cAAc,EAAE,iCAAiC;IACjDC,WAAW,EAAE;EACf,CAAC;EACDU,kCAAkC,EAAE;IAClCZ,EAAE,EAAE,wCAAwC;IAC5CC,cAAc,EAAE,gBAAgB;IAChCC,WAAW,EAAE;EACf,CAAC;EACD;EACAW,8BAA8B,EAAE;IAC9Bb,EAAE,EAAE,+BAA+B;IACnCC,cAAc,EAAE,mCAAmC;IACnDC,WAAW,EAAE;EACf,CAAC;EACD;EACAY,oCAAoC,EAAE;IACpCd,EAAE,EAAE,0CAA0C;IAC9CC,cAAc,EAAE,4CAA4C;IAC5DC,WAAW,EAAE;EACf,CAAC;EACDa,8BAA8B,EAAE;IAC9Bf,EAAE,EAAE,mCAAmC;IACvCC,cAAc,EAAE,oFAAoF;IACpGC,WAAW,EAAE;EACf,CAAC;EACDc,0BAA0B,EAAE;IAC1BhB,EAAE,EAAE,+BAA+B;IACnCC,cAAc,EAAE,yDAAyD;IACzEC,WAAW,EAAE;EACf,CAAC;EACDe,6BAA6B,EAAE;IAC7BjB,EAAE,EAAE,kCAAkC;IACtCC,cAAc,EAAE,+EAA+E;IAC/FC,WAAW,EAAE;EACf,CAAC;EACDgB,0BAA0B,EAAE;IAC1BlB,EAAE,EAAE,+BAA+B;IACnCC,cAAc,EAAE,oFAAoF;IACpGC,WAAW,EAAE;EACf,CAAC;EACDiB,oCAAoC,EAAE;IACpCnB,EAAE,EAAE,yCAAyC;IAC7CC,cAAc,EAAE,mFAAmF,GAC7F,2FAA2F,GAC3F,+DAA+D;IACrEC,WAAW,EAAE;EACf,CAAC;EACDkB,+BAA+B,EAAE;IAC/BpB,EAAE,EAAE,oCAAoC;IACxCC,cAAc,EAAE,mEAAmE;IACnFC,WAAW,EAAE;EACf;AACF,CAAC,CAAC;AAEF,eAAeJ,QAAQ","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/reset-password-popup/ResetPasswordHeader.js b/dist/forms/reset-password-popup/ResetPasswordHeader.js new file mode 100644 index 00000000..91882f27 --- /dev/null +++ b/dist/forms/reset-password-popup/ResetPasswordHeader.js @@ -0,0 +1,22 @@ +import React from 'react'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import messages from './messages'; + +/** + * Header component for the reset password form. + * Renders the heading for the reset password form along with a separator. + * @returns {JSX.Element} The rendered header component. + */ +const ResetPasswordHeader = () => { + const { + formatMessage + } = useIntl(); + return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("h2", { + className: "font-italic text-center display-1 m-0 text-dark-500 pb-0", + "data-testid": "forgot-password-heading" + }, formatMessage(messages.resetPasswordFormHeading)), /*#__PURE__*/React.createElement("hr", { + className: "separator my-3 my-sm-4" + })); +}; +export default ResetPasswordHeader; +//# sourceMappingURL=ResetPasswordHeader.js.map \ No newline at end of file diff --git a/dist/forms/reset-password-popup/ResetPasswordHeader.js.map b/dist/forms/reset-password-popup/ResetPasswordHeader.js.map new file mode 100644 index 00000000..b568560a --- /dev/null +++ b/dist/forms/reset-password-popup/ResetPasswordHeader.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ResetPasswordHeader.js","names":["React","useIntl","messages","ResetPasswordHeader","formatMessage","createElement","Fragment","className","resetPasswordFormHeading"],"sources":["../../../src/forms/reset-password-popup/ResetPasswordHeader.jsx"],"sourcesContent":["import React from 'react';\n\nimport { useIntl } from '@edx/frontend-platform/i18n';\n\nimport messages from './messages';\n\n/**\n * Header component for the reset password form.\n * Renders the heading for the reset password form along with a separator.\n * @returns {JSX.Element} The rendered header component.\n */\nconst ResetPasswordHeader = () => {\n const { formatMessage } = useIntl();\n\n return (\n <>\n \n {formatMessage(messages.resetPasswordFormHeading)}\n \n
\n \n );\n};\n\nexport default ResetPasswordHeader;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AAEzB,SAASC,OAAO,QAAQ,6BAA6B;AAErD,OAAOC,QAAQ,MAAM,YAAY;;AAEjC;AACA;AACA;AACA;AACA;AACA,MAAMC,mBAAmB,GAAGA,CAAA,KAAM;EAChC,MAAM;IAAEC;EAAc,CAAC,GAAGH,OAAO,CAAC,CAAC;EAEnC,oBACED,KAAA,CAAAK,aAAA,CAAAL,KAAA,CAAAM,QAAA,qBACEN,KAAA,CAAAK,aAAA;IACEE,SAAS,EAAC,0DAA0D;IACpE,eAAY;EAAyB,GAEpCH,aAAa,CAACF,QAAQ,CAACM,wBAAwB,CAC9C,CAAC,eACLR,KAAA,CAAAK,aAAA;IAAIE,SAAS,EAAC;EAAwB,CAAE,CACxC,CAAC;AAEP,CAAC;AAED,eAAeJ,mBAAmB","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/reset-password-popup/forgot-password/ForgotPasswordFailureAlert.js b/dist/forms/reset-password-popup/forgot-password/ForgotPasswordFailureAlert.js new file mode 100644 index 00000000..3894e447 --- /dev/null +++ b/dist/forms/reset-password-popup/forgot-password/ForgotPasswordFailureAlert.js @@ -0,0 +1,52 @@ +import React from 'react'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Alert } from '@openedx/paragon'; +import PropTypes from 'prop-types'; +import { FORBIDDEN_STATE, INTERNAL_SERVER_ERROR } from '../../../data/constants'; +import messages from '../messages'; +import { PASSWORD_RESET } from '../reset-password/data/constants'; + +/** + * Component responsible for showing error alert based on forgot password request status. + * @param {string} emailError + * @param {string} status + */ +const ForgotPasswordFailureAlert = _ref => { + let { + emailError = '', + status = '' + } = _ref; + const { + formatMessage + } = useIntl(); + let message = ''; + if (emailError) { + message = formatMessage(messages.forgotPasswordExtendFieldErrors, { + emailError + }); + } + switch (status) { + case INTERNAL_SERVER_ERROR: + message = formatMessage(messages.forgotPasswordInternalServerError); + break; + case PASSWORD_RESET.INVALID_TOKEN: + message = formatMessage(messages['invalid.token.error.message']); + break; + case FORBIDDEN_STATE: + message = formatMessage(messages.forgotPasswordRequestInProgressMessage); + break; + default: + break; + } + return message ? /*#__PURE__*/React.createElement(Alert, { + id: "forgot-password-failure-alert", + className: "mb-4", + variant: "danger" + }, /*#__PURE__*/React.createElement("p", null, message)) : null; +}; +ForgotPasswordFailureAlert.propTypes = { + emailError: PropTypes.string, + status: PropTypes.string +}; +export default ForgotPasswordFailureAlert; +//# sourceMappingURL=ForgotPasswordFailureAlert.js.map \ No newline at end of file diff --git a/dist/forms/reset-password-popup/forgot-password/ForgotPasswordFailureAlert.js.map b/dist/forms/reset-password-popup/forgot-password/ForgotPasswordFailureAlert.js.map new file mode 100644 index 00000000..c4cdacfd --- /dev/null +++ b/dist/forms/reset-password-popup/forgot-password/ForgotPasswordFailureAlert.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ForgotPasswordFailureAlert.js","names":["React","useIntl","Alert","PropTypes","FORBIDDEN_STATE","INTERNAL_SERVER_ERROR","messages","PASSWORD_RESET","ForgotPasswordFailureAlert","_ref","emailError","status","formatMessage","message","forgotPasswordExtendFieldErrors","forgotPasswordInternalServerError","INVALID_TOKEN","forgotPasswordRequestInProgressMessage","createElement","id","className","variant","propTypes","string"],"sources":["../../../../src/forms/reset-password-popup/forgot-password/ForgotPasswordFailureAlert.jsx"],"sourcesContent":["import React from 'react';\n\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport { Alert } from '@openedx/paragon';\nimport PropTypes from 'prop-types';\n\nimport { FORBIDDEN_STATE, INTERNAL_SERVER_ERROR } from '../../../data/constants';\nimport messages from '../messages';\nimport { PASSWORD_RESET } from '../reset-password/data/constants';\n\n/**\n * Component responsible for showing error alert based on forgot password request status.\n * @param {string} emailError\n * @param {string} status\n */\nconst ForgotPasswordFailureAlert = ({ emailError = '', status = '' }) => {\n const { formatMessage } = useIntl();\n let message = '';\n\n if (emailError) {\n message = formatMessage(messages.forgotPasswordExtendFieldErrors, { emailError });\n }\n\n switch (status) {\n case INTERNAL_SERVER_ERROR:\n message = formatMessage(messages.forgotPasswordInternalServerError);\n break;\n case PASSWORD_RESET.INVALID_TOKEN:\n message = formatMessage(messages['invalid.token.error.message']);\n break;\n case FORBIDDEN_STATE:\n message = formatMessage(messages.forgotPasswordRequestInProgressMessage);\n break;\n default:\n break;\n }\n\n return message ? (\n \n

{message}

\n
\n ) : null;\n};\n\nForgotPasswordFailureAlert.propTypes = {\n emailError: PropTypes.string,\n status: PropTypes.string,\n};\n\nexport default ForgotPasswordFailureAlert;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AAEzB,SAASC,OAAO,QAAQ,6BAA6B;AACrD,SAASC,KAAK,QAAQ,kBAAkB;AACxC,OAAOC,SAAS,MAAM,YAAY;AAElC,SAASC,eAAe,EAAEC,qBAAqB,QAAQ,yBAAyB;AAChF,OAAOC,QAAQ,MAAM,aAAa;AAClC,SAASC,cAAc,QAAQ,kCAAkC;;AAEjE;AACA;AACA;AACA;AACA;AACA,MAAMC,0BAA0B,GAAGC,IAAA,IAAsC;EAAA,IAArC;IAAEC,UAAU,GAAG,EAAE;IAAEC,MAAM,GAAG;EAAG,CAAC,GAAAF,IAAA;EAClE,MAAM;IAAEG;EAAc,CAAC,GAAGX,OAAO,CAAC,CAAC;EACnC,IAAIY,OAAO,GAAG,EAAE;EAEhB,IAAIH,UAAU,EAAE;IACdG,OAAO,GAAGD,aAAa,CAACN,QAAQ,CAACQ,+BAA+B,EAAE;MAAEJ;IAAW,CAAC,CAAC;EACnF;EAEA,QAAQC,MAAM;IACZ,KAAKN,qBAAqB;MACxBQ,OAAO,GAAGD,aAAa,CAACN,QAAQ,CAACS,iCAAiC,CAAC;MACnE;IACF,KAAKR,cAAc,CAACS,aAAa;MAC/BH,OAAO,GAAGD,aAAa,CAACN,QAAQ,CAAC,6BAA6B,CAAC,CAAC;MAChE;IACF,KAAKF,eAAe;MAClBS,OAAO,GAAGD,aAAa,CAACN,QAAQ,CAACW,sCAAsC,CAAC;MACxE;IACF;MACE;EACJ;EAEA,OAAOJ,OAAO,gBACZb,KAAA,CAAAkB,aAAA,CAAChB,KAAK;IAACiB,EAAE,EAAC,+BAA+B;IAACC,SAAS,EAAC,MAAM;IAACC,OAAO,EAAC;EAAQ,gBACzErB,KAAA,CAAAkB,aAAA,YAAIL,OAAW,CACV,CAAC,GACN,IAAI;AACV,CAAC;AAEDL,0BAA0B,CAACc,SAAS,GAAG;EACrCZ,UAAU,EAAEP,SAAS,CAACoB,MAAM;EAC5BZ,MAAM,EAAER,SAAS,CAACoB;AACpB,CAAC;AAED,eAAef,0BAA0B","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/reset-password-popup/forgot-password/ForgotPasswordSuccess.js b/dist/forms/reset-password-popup/forgot-password/ForgotPasswordSuccess.js new file mode 100644 index 00000000..10b1e0f2 --- /dev/null +++ b/dist/forms/reset-password-popup/forgot-password/ForgotPasswordSuccess.js @@ -0,0 +1,46 @@ +import React from 'react'; +import { getConfig } from '@edx/frontend-platform'; +import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; +import { Alert } from '@openedx/paragon'; +import PropTypes from 'prop-types'; +import messages from '../messages'; + +/** + * Component that renders a confirmation message after successfully sending the password reset email. + * + * @returns {JSX.Element} rendered confirmation message component . + */ +const ForgotPasswordSuccess = props => { + const { + formatMessage + } = useIntl(); + const { + email = '' + } = props; + return /*#__PURE__*/React.createElement("div", { + id: "forgot-password-success-msg", + className: "mb-5" + }, /*#__PURE__*/React.createElement("div", { + className: "text-gray-800 mb-3" + }, /*#__PURE__*/React.createElement("span", { + className: "font-weight-bold mr-2 h3 text-center d-block" + }, formatMessage(messages.emailSentMessage))), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement(FormattedMessage, { + id: "forgot.password.confirmation.message", + defaultMessage: "We sent an email to {email} with instructions to reset your password. If you do not receive a password reset message after 1 minute, verify that you entered the correct email address, or check your spam folder. If you need further assistance, visit {helpCenter}.", + description: "Forgot password confirmation message", + values: { + email: /*#__PURE__*/React.createElement("span", { + className: "data-hj-suppress" + }, email), + helpCenter: /*#__PURE__*/React.createElement(Alert.Link, { + href: getConfig().PASSWORD_RESET_SUPPORT_LINK, + target: "_blank" + }, formatMessage(messages.helpCenter)) + } + }))); +}; +ForgotPasswordSuccess.propTypes = { + email: PropTypes.string +}; +export default ForgotPasswordSuccess; +//# sourceMappingURL=ForgotPasswordSuccess.js.map \ No newline at end of file diff --git a/dist/forms/reset-password-popup/forgot-password/ForgotPasswordSuccess.js.map b/dist/forms/reset-password-popup/forgot-password/ForgotPasswordSuccess.js.map new file mode 100644 index 00000000..2f9ce182 --- /dev/null +++ b/dist/forms/reset-password-popup/forgot-password/ForgotPasswordSuccess.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ForgotPasswordSuccess.js","names":["React","getConfig","FormattedMessage","useIntl","Alert","PropTypes","messages","ForgotPasswordSuccess","props","formatMessage","email","createElement","id","className","emailSentMessage","defaultMessage","description","values","helpCenter","Link","href","PASSWORD_RESET_SUPPORT_LINK","target","propTypes","string"],"sources":["../../../../src/forms/reset-password-popup/forgot-password/ForgotPasswordSuccess.jsx"],"sourcesContent":["import React from 'react';\n\nimport { getConfig } from '@edx/frontend-platform';\nimport { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';\nimport { Alert } from '@openedx/paragon';\nimport PropTypes from 'prop-types';\n\nimport messages from '../messages';\n\n/**\n * Component that renders a confirmation message after successfully sending the password reset email.\n *\n * @returns {JSX.Element} rendered confirmation message component .\n */\nconst ForgotPasswordSuccess = (props) => {\n const { formatMessage } = useIntl();\n const { email = '' } = props;\n\n return (\n
\n
\n \n {formatMessage(messages.emailSentMessage)}\n \n
\n

\n {email},\n helpCenter: (\n \n {formatMessage(messages.helpCenter)}\n \n ),\n }}\n />\n

\n
\n );\n};\n\nForgotPasswordSuccess.propTypes = {\n email: PropTypes.string,\n};\n\nexport default ForgotPasswordSuccess;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AAEzB,SAASC,SAAS,QAAQ,wBAAwB;AAClD,SAASC,gBAAgB,EAAEC,OAAO,QAAQ,6BAA6B;AACvE,SAASC,KAAK,QAAQ,kBAAkB;AACxC,OAAOC,SAAS,MAAM,YAAY;AAElC,OAAOC,QAAQ,MAAM,aAAa;;AAElC;AACA;AACA;AACA;AACA;AACA,MAAMC,qBAAqB,GAAIC,KAAK,IAAK;EACvC,MAAM;IAAEC;EAAc,CAAC,GAAGN,OAAO,CAAC,CAAC;EACnC,MAAM;IAAEO,KAAK,GAAG;EAAG,CAAC,GAAGF,KAAK;EAE5B,oBACER,KAAA,CAAAW,aAAA;IAAKC,EAAE,EAAC,6BAA6B;IAACC,SAAS,EAAC;EAAM,gBACpDb,KAAA,CAAAW,aAAA;IAAKE,SAAS,EAAC;EAAoB,gBACjCb,KAAA,CAAAW,aAAA;IAAME,SAAS,EAAC;EAA8C,GAC3DJ,aAAa,CAACH,QAAQ,CAACQ,gBAAgB,CACpC,CACH,CAAC,eACNd,KAAA,CAAAW,aAAA,yBACEX,KAAA,CAAAW,aAAA,CAACT,gBAAgB;IACfU,EAAE,EAAC,sCAAsC;IACzCG,cAAc,EAAC,wQAGK;IACpBC,WAAW,EAAC,sCAAsC;IAClDC,MAAM,EAAE;MACNP,KAAK,eAAEV,KAAA,CAAAW,aAAA;QAAME,SAAS,EAAC;MAAkB,GAAEH,KAAY,CAAC;MACxDQ,UAAU,eACRlB,KAAA,CAAAW,aAAA,CAACP,KAAK,CAACe,IAAI;QAACC,IAAI,EAAEnB,SAAS,CAAC,CAAC,CAACoB,2BAA4B;QAACC,MAAM,EAAC;MAAQ,GACvEb,aAAa,CAACH,QAAQ,CAACY,UAAU,CACxB;IAEhB;EAAE,CACH,CACA,CACA,CAAC;AAEV,CAAC;AAEDX,qBAAqB,CAACgB,SAAS,GAAG;EAChCb,KAAK,EAAEL,SAAS,CAACmB;AACnB,CAAC;AAED,eAAejB,qBAAqB","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/reset-password-popup/forgot-password/data/reducers.js b/dist/forms/reset-password-popup/forgot-password/data/reducers.js new file mode 100644 index 00000000..5c4fc688 --- /dev/null +++ b/dist/forms/reset-password-popup/forgot-password/data/reducers.js @@ -0,0 +1,50 @@ +/** + * Redux slice for managing forgot password state. + * This slice handles the forgot password process, including the submission state, + * password reset success, and any errors that may occur. + */ + +import { createSlice } from '@reduxjs/toolkit'; +import { COMPLETE_STATE, DEFAULT_STATE, FORBIDDEN_STATE, INTERNAL_SERVER_ERROR, PENDING_STATE } from '../../../../data/constants'; +export const storeName = 'forgotPassword'; +export const FORGOT_PASSWORD_SLICE_NAME = 'forgotPassword'; +export const forgotPasswordInitialState = { + status: DEFAULT_STATE +}; +export const forgotPasswordSlice = createSlice({ + name: FORGOT_PASSWORD_SLICE_NAME, + initialState: forgotPasswordInitialState, + reducers: { + forgotPassword: state => { + state.status = PENDING_STATE; + }, + forgotPasswordSuccess: state => { + state.status = COMPLETE_STATE; + }, + forgotPasswordForbidden: state => { + state.status = FORBIDDEN_STATE; + }, + forgotPasswordFailed: state => { + state.status = INTERNAL_SERVER_ERROR; + }, + forgotPasswordClearStatus: state => { + state.status = DEFAULT_STATE; + }, + forgotPassweordTokenInvalidFailure: (state, _ref) => { + let { + payload + } = _ref; + state.status = payload; + } + } +}); +export const { + forgotPassword, + forgotPasswordSuccess, + forgotPasswordForbidden, + forgotPasswordFailed, + forgotPasswordClearStatus, + forgotPassweordTokenInvalidFailure +} = forgotPasswordSlice.actions; +export default forgotPasswordSlice.reducer; +//# sourceMappingURL=reducers.js.map \ No newline at end of file diff --git a/dist/forms/reset-password-popup/forgot-password/data/reducers.js.map b/dist/forms/reset-password-popup/forgot-password/data/reducers.js.map new file mode 100644 index 00000000..9663768a --- /dev/null +++ b/dist/forms/reset-password-popup/forgot-password/data/reducers.js.map @@ -0,0 +1 @@ +{"version":3,"file":"reducers.js","names":["createSlice","COMPLETE_STATE","DEFAULT_STATE","FORBIDDEN_STATE","INTERNAL_SERVER_ERROR","PENDING_STATE","storeName","FORGOT_PASSWORD_SLICE_NAME","forgotPasswordInitialState","status","forgotPasswordSlice","name","initialState","reducers","forgotPassword","state","forgotPasswordSuccess","forgotPasswordForbidden","forgotPasswordFailed","forgotPasswordClearStatus","forgotPassweordTokenInvalidFailure","_ref","payload","actions","reducer"],"sources":["../../../../../src/forms/reset-password-popup/forgot-password/data/reducers.js"],"sourcesContent":["/**\n * Redux slice for managing forgot password state.\n * This slice handles the forgot password process, including the submission state,\n * password reset success, and any errors that may occur.\n */\n\nimport { createSlice } from '@reduxjs/toolkit';\n\nimport {\n COMPLETE_STATE,\n DEFAULT_STATE,\n FORBIDDEN_STATE,\n INTERNAL_SERVER_ERROR,\n PENDING_STATE,\n} from '../../../../data/constants';\n\nexport const storeName = 'forgotPassword';\nexport const FORGOT_PASSWORD_SLICE_NAME = 'forgotPassword';\n\nexport const forgotPasswordInitialState = {\n status: DEFAULT_STATE,\n};\n\nexport const forgotPasswordSlice = createSlice({\n name: FORGOT_PASSWORD_SLICE_NAME,\n initialState: forgotPasswordInitialState,\n reducers: {\n forgotPassword: (state) => {\n state.status = PENDING_STATE;\n },\n forgotPasswordSuccess: (state) => {\n state.status = COMPLETE_STATE;\n },\n forgotPasswordForbidden: (state) => {\n state.status = FORBIDDEN_STATE;\n },\n forgotPasswordFailed: (state) => {\n state.status = INTERNAL_SERVER_ERROR;\n },\n forgotPasswordClearStatus: (state) => {\n state.status = DEFAULT_STATE;\n },\n forgotPassweordTokenInvalidFailure: (state, { payload }) => {\n state.status = payload;\n },\n },\n});\n\nexport const {\n forgotPassword,\n forgotPasswordSuccess,\n forgotPasswordForbidden,\n forgotPasswordFailed,\n forgotPasswordClearStatus,\n forgotPassweordTokenInvalidFailure,\n} = forgotPasswordSlice.actions;\n\nexport default forgotPasswordSlice.reducer;\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;;AAEA,SAASA,WAAW,QAAQ,kBAAkB;AAE9C,SACEC,cAAc,EACdC,aAAa,EACbC,eAAe,EACfC,qBAAqB,EACrBC,aAAa,QACR,4BAA4B;AAEnC,OAAO,MAAMC,SAAS,GAAG,gBAAgB;AACzC,OAAO,MAAMC,0BAA0B,GAAG,gBAAgB;AAE1D,OAAO,MAAMC,0BAA0B,GAAG;EACxCC,MAAM,EAAEP;AACV,CAAC;AAED,OAAO,MAAMQ,mBAAmB,GAAGV,WAAW,CAAC;EAC7CW,IAAI,EAAEJ,0BAA0B;EAChCK,YAAY,EAAEJ,0BAA0B;EACxCK,QAAQ,EAAE;IACRC,cAAc,EAAGC,KAAK,IAAK;MACzBA,KAAK,CAACN,MAAM,GAAGJ,aAAa;IAC9B,CAAC;IACDW,qBAAqB,EAAGD,KAAK,IAAK;MAChCA,KAAK,CAACN,MAAM,GAAGR,cAAc;IAC/B,CAAC;IACDgB,uBAAuB,EAAGF,KAAK,IAAK;MAClCA,KAAK,CAACN,MAAM,GAAGN,eAAe;IAChC,CAAC;IACDe,oBAAoB,EAAGH,KAAK,IAAK;MAC/BA,KAAK,CAACN,MAAM,GAAGL,qBAAqB;IACtC,CAAC;IACDe,yBAAyB,EAAGJ,KAAK,IAAK;MACpCA,KAAK,CAACN,MAAM,GAAGP,aAAa;IAC9B,CAAC;IACDkB,kCAAkC,EAAEA,CAACL,KAAK,EAAAM,IAAA,KAAkB;MAAA,IAAhB;QAAEC;MAAQ,CAAC,GAAAD,IAAA;MACrDN,KAAK,CAACN,MAAM,GAAGa,OAAO;IACxB;EACF;AACF,CAAC,CAAC;AAEF,OAAO,MAAM;EACXR,cAAc;EACdE,qBAAqB;EACrBC,uBAAuB;EACvBC,oBAAoB;EACpBC,yBAAyB;EACzBC;AACF,CAAC,GAAGV,mBAAmB,CAACa,OAAO;AAE/B,eAAeb,mBAAmB,CAACc,OAAO","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/reset-password-popup/forgot-password/data/sagas.js b/dist/forms/reset-password-popup/forgot-password/data/sagas.js new file mode 100644 index 00000000..35976113 --- /dev/null +++ b/dist/forms/reset-password-popup/forgot-password/data/sagas.js @@ -0,0 +1,27 @@ +import { logError, logInfo } from '@edx/frontend-platform/logging'; +import { call, put, takeEvery } from 'redux-saga/effects'; +import { forgotPassword, forgotPasswordFailed, forgotPasswordForbidden, forgotPasswordSuccess } from './reducers'; +import forgotPasswordService from './service'; + +/** + * Saga function for handling forgot password actions. + * @param {object} action - The Redux action object containing the payload. + */ +export function* handleForgotPassword(action) { + try { + yield call(forgotPasswordService, action.payload); + yield put(forgotPasswordSuccess(action.payload)); + } catch (e) { + if (e.response && e.response.status === 403) { + yield put(forgotPasswordForbidden()); + logInfo(e); + } else { + yield put(forgotPasswordFailed()); + logError(e); + } + } +} +export default function* saga() { + yield takeEvery(forgotPassword.type, handleForgotPassword); +} +//# sourceMappingURL=sagas.js.map \ No newline at end of file diff --git a/dist/forms/reset-password-popup/forgot-password/data/sagas.js.map b/dist/forms/reset-password-popup/forgot-password/data/sagas.js.map new file mode 100644 index 00000000..846eed50 --- /dev/null +++ b/dist/forms/reset-password-popup/forgot-password/data/sagas.js.map @@ -0,0 +1 @@ +{"version":3,"file":"sagas.js","names":["logError","logInfo","call","put","takeEvery","forgotPassword","forgotPasswordFailed","forgotPasswordForbidden","forgotPasswordSuccess","forgotPasswordService","handleForgotPassword","action","payload","e","response","status","saga","type"],"sources":["../../../../../src/forms/reset-password-popup/forgot-password/data/sagas.js"],"sourcesContent":["import { logError, logInfo } from '@edx/frontend-platform/logging';\nimport { call, put, takeEvery } from 'redux-saga/effects';\n\nimport {\n forgotPassword,\n forgotPasswordFailed,\n forgotPasswordForbidden,\n forgotPasswordSuccess,\n} from './reducers';\nimport forgotPasswordService from './service';\n\n/**\n * Saga function for handling forgot password actions.\n * @param {object} action - The Redux action object containing the payload.\n */\nexport function* handleForgotPassword(action) {\n try {\n yield call(forgotPasswordService, action.payload);\n\n yield put(forgotPasswordSuccess(action.payload));\n } catch (e) {\n if (e.response && e.response.status === 403) {\n yield put(forgotPasswordForbidden());\n logInfo(e);\n } else {\n yield put(forgotPasswordFailed());\n logError(e);\n }\n }\n}\n\nexport default function* saga() {\n yield takeEvery(forgotPassword.type, handleForgotPassword);\n}\n"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,OAAO,QAAQ,gCAAgC;AAClE,SAASC,IAAI,EAAEC,GAAG,EAAEC,SAAS,QAAQ,oBAAoB;AAEzD,SACEC,cAAc,EACdC,oBAAoB,EACpBC,uBAAuB,EACvBC,qBAAqB,QAChB,YAAY;AACnB,OAAOC,qBAAqB,MAAM,WAAW;;AAE7C;AACA;AACA;AACA;AACA,OAAO,UAAUC,oBAAoBA,CAACC,MAAM,EAAE;EAC5C,IAAI;IACF,MAAMT,IAAI,CAACO,qBAAqB,EAAEE,MAAM,CAACC,OAAO,CAAC;IAEjD,MAAMT,GAAG,CAACK,qBAAqB,CAACG,MAAM,CAACC,OAAO,CAAC,CAAC;EAClD,CAAC,CAAC,OAAOC,CAAC,EAAE;IACV,IAAIA,CAAC,CAACC,QAAQ,IAAID,CAAC,CAACC,QAAQ,CAACC,MAAM,KAAK,GAAG,EAAE;MAC3C,MAAMZ,GAAG,CAACI,uBAAuB,CAAC,CAAC,CAAC;MACpCN,OAAO,CAACY,CAAC,CAAC;IACZ,CAAC,MAAM;MACL,MAAMV,GAAG,CAACG,oBAAoB,CAAC,CAAC,CAAC;MACjCN,QAAQ,CAACa,CAAC,CAAC;IACb;EACF;AACF;AAEA,eAAe,UAAUG,IAAIA,CAAA,EAAG;EAC9B,MAAMZ,SAAS,CAACC,cAAc,CAACY,IAAI,EAAEP,oBAAoB,CAAC;AAC5D","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/reset-password-popup/forgot-password/data/service.js b/dist/forms/reset-password-popup/forgot-password/data/service.js new file mode 100644 index 00000000..9d332d4f --- /dev/null +++ b/dist/forms/reset-password-popup/forgot-password/data/service.js @@ -0,0 +1,29 @@ +import { getConfig } from '@edx/frontend-platform'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; +import formurlencoded from 'form-urlencoded'; + +/** + * Function to handle forgot password requests. + * This function sends a POST request to the LMS backend to initiate a password reset for the provided email. + * + * @param {string} email - The email address for which the password reset is requested. + * @returns {Promise} - A promise that resolves with the response data from the LMS backend. + * @throws {Error} - Throws an error if the HTTP request fails. + */ +export default async function forgotPasswordService(email) { + const requestConfig = { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + isPublic: true + }; + const { + data + } = await getAuthenticatedHttpClient().post(`${getConfig().LMS_BASE_URL}/account/password`, formurlencoded({ + email + }), requestConfig).catch(e => { + throw e; + }); + return data; +} +//# sourceMappingURL=service.js.map \ No newline at end of file diff --git a/dist/forms/reset-password-popup/forgot-password/data/service.js.map b/dist/forms/reset-password-popup/forgot-password/data/service.js.map new file mode 100644 index 00000000..c8034232 --- /dev/null +++ b/dist/forms/reset-password-popup/forgot-password/data/service.js.map @@ -0,0 +1 @@ +{"version":3,"file":"service.js","names":["getConfig","getAuthenticatedHttpClient","formurlencoded","forgotPasswordService","email","requestConfig","headers","isPublic","data","post","LMS_BASE_URL","catch","e"],"sources":["../../../../../src/forms/reset-password-popup/forgot-password/data/service.js"],"sourcesContent":["import { getConfig } from '@edx/frontend-platform';\nimport { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';\nimport formurlencoded from 'form-urlencoded';\n\n/**\n * Function to handle forgot password requests.\n * This function sends a POST request to the LMS backend to initiate a password reset for the provided email.\n *\n * @param {string} email - The email address for which the password reset is requested.\n * @returns {Promise} - A promise that resolves with the response data from the LMS backend.\n * @throws {Error} - Throws an error if the HTTP request fails.\n */\nexport default async function forgotPasswordService(email) {\n const requestConfig = {\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n isPublic: true,\n };\n\n const { data } = await getAuthenticatedHttpClient()\n .post(\n `${getConfig().LMS_BASE_URL}/account/password`,\n formurlencoded({ email }),\n requestConfig,\n )\n .catch((e) => {\n throw (e);\n });\n\n return data;\n}\n"],"mappings":"AAAA,SAASA,SAAS,QAAQ,wBAAwB;AAClD,SAASC,0BAA0B,QAAQ,6BAA6B;AACxE,OAAOC,cAAc,MAAM,iBAAiB;;AAE5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,eAAeC,qBAAqBA,CAACC,KAAK,EAAE;EACzD,MAAMC,aAAa,GAAG;IACpBC,OAAO,EAAE;MAAE,cAAc,EAAE;IAAoC,CAAC;IAChEC,QAAQ,EAAE;EACZ,CAAC;EAED,MAAM;IAAEC;EAAK,CAAC,GAAG,MAAMP,0BAA0B,CAAC,CAAC,CAChDQ,IAAI,CACF,GAAET,SAAS,CAAC,CAAC,CAACU,YAAa,mBAAkB,EAC9CR,cAAc,CAAC;IAAEE;EAAM,CAAC,CAAC,EACzBC,aACF,CAAC,CACAM,KAAK,CAAEC,CAAC,IAAK;IACZ,MAAOA,CAAC;EACV,CAAC,CAAC;EAEJ,OAAOJ,IAAI;AACb","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/reset-password-popup/forgot-password/data/utils.js b/dist/forms/reset-password-popup/forgot-password/data/utils.js new file mode 100644 index 00000000..3df2a0be --- /dev/null +++ b/dist/forms/reset-password-popup/forgot-password/data/utils.js @@ -0,0 +1,24 @@ +import { VALID_EMAIL_REGEX } from '../../../../data/constants'; +import messages from '../../messages'; + +/** + * Email Validation Function. It checks if the provided email value is either empty or does not match + * the regular expression for a valid email format. If the value is invalid, it returns + * a corresponding error message formatted using the provided `formatMessage` function. + * + * @param {string} value - The email value to be validated. + * @param {function} formatMessage - The function to format the error message. + * @returns {string} - An error message if the email value is invalid, otherwise an empty string. + */ +const getValidationMessage = (value, formatMessage) => { + const emailRegex = new RegExp(VALID_EMAIL_REGEX, 'i'); + let error = ''; + if (value === undefined || value === '') { + error = formatMessage(messages.forgotPasswordEmptyEmailFieldError); + } else if (!emailRegex.test(value)) { + error = formatMessage(messages.forgotPasswordPageInvalidEmaiMessage); + } + return error; +}; +export default getValidationMessage; +//# sourceMappingURL=utils.js.map \ No newline at end of file diff --git a/dist/forms/reset-password-popup/forgot-password/data/utils.js.map b/dist/forms/reset-password-popup/forgot-password/data/utils.js.map new file mode 100644 index 00000000..06e8f024 --- /dev/null +++ b/dist/forms/reset-password-popup/forgot-password/data/utils.js.map @@ -0,0 +1 @@ +{"version":3,"file":"utils.js","names":["VALID_EMAIL_REGEX","messages","getValidationMessage","value","formatMessage","emailRegex","RegExp","error","undefined","forgotPasswordEmptyEmailFieldError","test","forgotPasswordPageInvalidEmaiMessage"],"sources":["../../../../../src/forms/reset-password-popup/forgot-password/data/utils.js"],"sourcesContent":["import { VALID_EMAIL_REGEX } from '../../../../data/constants';\nimport messages from '../../messages';\n\n/**\n * Email Validation Function. It checks if the provided email value is either empty or does not match\n * the regular expression for a valid email format. If the value is invalid, it returns\n * a corresponding error message formatted using the provided `formatMessage` function.\n *\n * @param {string} value - The email value to be validated.\n * @param {function} formatMessage - The function to format the error message.\n * @returns {string} - An error message if the email value is invalid, otherwise an empty string.\n */\nconst getValidationMessage = (value, formatMessage) => {\n const emailRegex = new RegExp(VALID_EMAIL_REGEX, 'i');\n let error = '';\n if (value === undefined || value === '') {\n error = formatMessage(messages.forgotPasswordEmptyEmailFieldError);\n } else if (!emailRegex.test(value)) {\n error = formatMessage(messages.forgotPasswordPageInvalidEmaiMessage);\n }\n return error;\n};\n\nexport default getValidationMessage;\n"],"mappings":"AAAA,SAASA,iBAAiB,QAAQ,4BAA4B;AAC9D,OAAOC,QAAQ,MAAM,gBAAgB;;AAErC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,oBAAoB,GAAGA,CAACC,KAAK,EAAEC,aAAa,KAAK;EACrD,MAAMC,UAAU,GAAG,IAAIC,MAAM,CAACN,iBAAiB,EAAE,GAAG,CAAC;EACrD,IAAIO,KAAK,GAAG,EAAE;EACd,IAAIJ,KAAK,KAAKK,SAAS,IAAIL,KAAK,KAAK,EAAE,EAAE;IACvCI,KAAK,GAAGH,aAAa,CAACH,QAAQ,CAACQ,kCAAkC,CAAC;EACpE,CAAC,MAAM,IAAI,CAACJ,UAAU,CAACK,IAAI,CAACP,KAAK,CAAC,EAAE;IAClCI,KAAK,GAAGH,aAAa,CAACH,QAAQ,CAACU,oCAAoC,CAAC;EACtE;EACA,OAAOJ,KAAK;AACd,CAAC;AAED,eAAeL,oBAAoB","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/reset-password-popup/forgot-password/index.js b/dist/forms/reset-password-popup/forgot-password/index.js new file mode 100644 index 00000000..b53f3541 --- /dev/null +++ b/dist/forms/reset-password-popup/forgot-password/index.js @@ -0,0 +1,159 @@ +function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } +function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } +function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); } +function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } +import React, { useEffect, useRef, useState } from 'react'; +import { getConfig } from '@edx/frontend-platform'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Button, Container, Form, StatefulButton } from '@openedx/paragon'; +import { forgotPassword, forgotPasswordClearStatus } from './data/reducers'; +import getValidationMessage from './data/utils'; +import ForgotPasswordFailureAlert from './ForgotPasswordFailureAlert'; +import ForgotPasswordSuccess from './ForgotPasswordSuccess'; +import { setCurrentOpenedForm } from '../../../authn-component/data/reducers'; +import { InlineLink } from '../../../common-ui'; +import { COMPLETE_STATE, DEFAULT_STATE, LOGIN_FORM } from '../../../data/constants'; +import { useDispatch, useSelector } from '../../../data/storeHooks'; +import { trackForgotPasswordPageEvent, trackForgotPasswordPageViewed } from '../../../tracking/trackers/forgotpassword'; +import EmailField from '../../fields/email-field'; +import { NUDGE_PASSWORD_CHANGE, REQUIRE_PASSWORD_CHANGE } from '../../login-popup/data/constants'; +import { loginErrorClear } from '../../login-popup/data/reducers'; +import messages from '../messages'; +import ResetPasswordHeader from '../ResetPasswordHeader'; +import '../index.scss'; +const ForgotPasswordForm = () => { + const { + formatMessage + } = useIntl(); + const dispatch = useDispatch(); + const status = useSelector(state => state.forgotPassword?.status); + const loginErrorCode = useSelector(state => state.login.loginError?.errorCode); + const [formErrors, setFormErrors] = useState(''); + const [formFields, setFormFields] = useState({ + email: '' + }); + const [isSuccess, setIsSuccess] = useState(false); + const emailRef = useRef(null); + const nudgePasswordChangeRef = useRef(null); + const requirePasswordChangeRef = useRef(null); + useEffect(() => { + trackForgotPasswordPageViewed(); + trackForgotPasswordPageEvent(); + }, []); + const handleOnChange = event => { + const { + name + } = event.target; + const value = event.target.type === 'checkbox' ? event.target.checked : event.target.value; + setFormFields(prevState => _objectSpread(_objectSpread({}, prevState), {}, { + [name]: value + })); + }; + const handleErrorChange = (fieldName, error) => { + setFormErrors(error); + }; + const backToLogin = e => { + e.preventDefault(); + dispatch(forgotPasswordClearStatus()); + dispatch(loginErrorClear()); + dispatch(setCurrentOpenedForm(LOGIN_FORM)); + }; + useEffect(() => { + if (status === COMPLETE_STATE) { + setFormErrors(''); + setIsSuccess(true); + } + }, [status]); + useEffect(() => { + if (loginErrorCode === NUDGE_PASSWORD_CHANGE && nudgePasswordChangeRef.current) { + nudgePasswordChangeRef.current.focus(); + } else if (loginErrorCode === REQUIRE_PASSWORD_CHANGE && requirePasswordChangeRef.current) { + requirePasswordChangeRef.current.focus(); + } else { + emailRef.current.focus(); + } + }, [loginErrorCode]); + const handleSubmit = e => { + e.preventDefault(); + setFormErrors(''); + const error = getValidationMessage(formFields.email, formatMessage); + if (error) { + setFormErrors(error); + } else { + dispatch(forgotPassword(formFields.email)); + } + }; + return /*#__PURE__*/React.createElement(Container, { + size: "lg", + className: "authn__popup-container overflow-auto" + }, /*#__PURE__*/React.createElement(ResetPasswordHeader, null), /*#__PURE__*/React.createElement(ForgotPasswordFailureAlert, { + emailError: formErrors, + status: status + }), status === DEFAULT_STATE && loginErrorCode === REQUIRE_PASSWORD_CHANGE && /*#__PURE__*/React.createElement("p", { + "aria-live": "assertive", + tabIndex: "-1", + ref: requirePasswordChangeRef, + "data-testid": "require-password-change-message" + }, formatMessage(messages.vulnerablePasswordBlockedMessage)), status === DEFAULT_STATE && loginErrorCode === NUDGE_PASSWORD_CHANGE && /*#__PURE__*/React.createElement("p", { + tabIndex: "-1", + "aria-live": "assertive", + ref: nudgePasswordChangeRef, + "data-testid": "nudge-password-change-message" + }, formatMessage(messages.vulnerablePasswordWarnedMessage)), !isSuccess && /*#__PURE__*/React.createElement(Form, { + id: "forgot-password-form", + name: "reset-password-form", + className: "d-flex flex-column" + }, /*#__PURE__*/React.createElement(EmailField, { + name: "email", + value: formFields.email, + handleChange: handleOnChange, + handleErrorChange: handleErrorChange, + autoComplete: "email", + errorMessage: formErrors, + floatingLabel: formatMessage(messages.forgotPasswordFormEmailFieldLabel), + isRegistration: false, + validateEmailFromBackend: false, + ref: emailRef + }), /*#__PURE__*/React.createElement(StatefulButton, { + id: "reset-password-user", + name: "reset-password-user", + type: "submit", + variant: "primary", + className: "align-self-end forgot-password-form__submit-btn__width authn-btn__pill-shaped", + state: status, + labels: { + default: formatMessage(messages.resetPasswordFormSubmitButton), + pending: '' + }, + onClick: handleSubmit, + onMouseDown: e => e.preventDefault() + }), /*#__PURE__*/React.createElement("div", { + className: "my-4" + }, /*#__PURE__*/React.createElement(InlineLink, { + className: "mb-2", + destination: getConfig().LOGIN_ISSUE_SUPPORT_LINK, + linkHelpText: formatMessage(messages.resetPasswordFormNeedHelpText), + linkText: formatMessage(messages.resetPasswordFormHelpCenterLink), + targetBlank: true + }), /*#__PURE__*/React.createElement(InlineLink, { + className: "font-weight-normal small", + destination: `mailto:${getConfig().INFO_EMAIL}`, + linkHelpText: formatMessage(messages.resetPasswordFormAdditionalHelpText), + linkText: getConfig().INFO_EMAIL + }))), isSuccess && /*#__PURE__*/React.createElement(ForgotPasswordSuccess, { + email: formFields.email + }), /*#__PURE__*/React.createElement("div", { + className: "text-center mt-4.5" + }, loginErrorCode !== REQUIRE_PASSWORD_CHANGE && /*#__PURE__*/React.createElement(Button, { + id: "reset-password-back-to-login", + name: "reset-password-back-to-login", + variant: "tertiary", + type: "submit", + className: "align-self-center back-to-login__button authn-btn__pill-shaped", + onClick: backToLogin, + onMouseDown: e => e.preventDefault() + }, formatMessage(messages.resetPasswordBackToLoginButton)))); +}; +export default ForgotPasswordForm; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/forms/reset-password-popup/forgot-password/index.js.map b/dist/forms/reset-password-popup/forgot-password/index.js.map new file mode 100644 index 00000000..3620993d --- /dev/null +++ b/dist/forms/reset-password-popup/forgot-password/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["React","useEffect","useRef","useState","getConfig","useIntl","Button","Container","Form","StatefulButton","forgotPassword","forgotPasswordClearStatus","getValidationMessage","ForgotPasswordFailureAlert","ForgotPasswordSuccess","setCurrentOpenedForm","InlineLink","COMPLETE_STATE","DEFAULT_STATE","LOGIN_FORM","useDispatch","useSelector","trackForgotPasswordPageEvent","trackForgotPasswordPageViewed","EmailField","NUDGE_PASSWORD_CHANGE","REQUIRE_PASSWORD_CHANGE","loginErrorClear","messages","ResetPasswordHeader","ForgotPasswordForm","formatMessage","dispatch","status","state","loginErrorCode","login","loginError","errorCode","formErrors","setFormErrors","formFields","setFormFields","email","isSuccess","setIsSuccess","emailRef","nudgePasswordChangeRef","requirePasswordChangeRef","handleOnChange","event","name","target","value","type","checked","prevState","_objectSpread","handleErrorChange","fieldName","error","backToLogin","e","preventDefault","current","focus","handleSubmit","createElement","size","className","emailError","tabIndex","ref","vulnerablePasswordBlockedMessage","vulnerablePasswordWarnedMessage","id","handleChange","autoComplete","errorMessage","floatingLabel","forgotPasswordFormEmailFieldLabel","isRegistration","validateEmailFromBackend","variant","labels","default","resetPasswordFormSubmitButton","pending","onClick","onMouseDown","destination","LOGIN_ISSUE_SUPPORT_LINK","linkHelpText","resetPasswordFormNeedHelpText","linkText","resetPasswordFormHelpCenterLink","targetBlank","INFO_EMAIL","resetPasswordFormAdditionalHelpText","resetPasswordBackToLoginButton"],"sources":["../../../../src/forms/reset-password-popup/forgot-password/index.jsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\n\nimport { getConfig } from '@edx/frontend-platform';\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport {\n Button, Container, Form, StatefulButton,\n} from '@openedx/paragon';\n\nimport { forgotPassword, forgotPasswordClearStatus } from './data/reducers';\nimport getValidationMessage from './data/utils';\nimport ForgotPasswordFailureAlert from './ForgotPasswordFailureAlert';\nimport ForgotPasswordSuccess from './ForgotPasswordSuccess';\nimport { setCurrentOpenedForm } from '../../../authn-component/data/reducers';\nimport { InlineLink } from '../../../common-ui';\nimport { COMPLETE_STATE, DEFAULT_STATE, LOGIN_FORM } from '../../../data/constants';\nimport { useDispatch, useSelector } from '../../../data/storeHooks';\nimport { trackForgotPasswordPageEvent, trackForgotPasswordPageViewed } from '../../../tracking/trackers/forgotpassword';\nimport EmailField from '../../fields/email-field';\nimport { NUDGE_PASSWORD_CHANGE, REQUIRE_PASSWORD_CHANGE } from '../../login-popup/data/constants';\nimport { loginErrorClear } from '../../login-popup/data/reducers';\nimport messages from '../messages';\nimport ResetPasswordHeader from '../ResetPasswordHeader';\nimport '../index.scss';\n\nconst ForgotPasswordForm = () => {\n const { formatMessage } = useIntl();\n const dispatch = useDispatch();\n const status = useSelector(state => state.forgotPassword?.status);\n const loginErrorCode = useSelector(state => state.login.loginError?.errorCode);\n\n const [formErrors, setFormErrors] = useState('');\n const [formFields, setFormFields] = useState({ email: '' });\n const [isSuccess, setIsSuccess] = useState(false);\n\n const emailRef = useRef(null);\n const nudgePasswordChangeRef = useRef(null);\n const requirePasswordChangeRef = useRef(null);\n\n useEffect(() => {\n trackForgotPasswordPageViewed();\n trackForgotPasswordPageEvent();\n }, []);\n\n const handleOnChange = (event) => {\n const { name } = event.target;\n const value = event.target.type === 'checkbox' ? event.target.checked : event.target.value;\n setFormFields(prevState => ({ ...prevState, [name]: value }));\n };\n const handleErrorChange = (fieldName, error) => {\n setFormErrors(error);\n };\n\n const backToLogin = (e) => {\n e.preventDefault();\n dispatch(forgotPasswordClearStatus());\n dispatch(loginErrorClear());\n dispatch(setCurrentOpenedForm(LOGIN_FORM));\n };\n\n useEffect(() => {\n if (status === COMPLETE_STATE) {\n setFormErrors('');\n setIsSuccess(true);\n }\n }, [status]);\n\n useEffect(() => {\n if (loginErrorCode === NUDGE_PASSWORD_CHANGE && nudgePasswordChangeRef.current) {\n nudgePasswordChangeRef.current.focus();\n } else if (loginErrorCode === REQUIRE_PASSWORD_CHANGE && requirePasswordChangeRef.current) {\n requirePasswordChangeRef.current.focus();\n } else {\n emailRef.current.focus();\n }\n }, [loginErrorCode]);\n\n const handleSubmit = (e) => {\n e.preventDefault();\n setFormErrors('');\n\n const error = getValidationMessage(formFields.email, formatMessage);\n if (error) {\n setFormErrors(error);\n } else {\n dispatch(forgotPassword(formFields.email));\n }\n };\n\n return (\n \n \n \n {status === DEFAULT_STATE && loginErrorCode === REQUIRE_PASSWORD_CHANGE && (\n \n {formatMessage(messages.vulnerablePasswordBlockedMessage)}\n

\n )}\n {status === DEFAULT_STATE && loginErrorCode === NUDGE_PASSWORD_CHANGE && (\n \n {formatMessage(messages.vulnerablePasswordWarnedMessage)}\n

\n )}\n {!isSuccess && (\n
\n \n e.preventDefault()}\n />\n\n
\n \n \n
\n \n )}\n {isSuccess && (\n \n )}\n
\n {loginErrorCode !== REQUIRE_PASSWORD_CHANGE && (\n e.preventDefault()}\n >\n {formatMessage(messages.resetPasswordBackToLoginButton)}\n \n )}\n
\n
\n );\n};\n\nexport default ForgotPasswordForm;\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/reset-password-popup/index.scss b/dist/forms/reset-password-popup/index.scss new file mode 100644 index 00000000..e489d986 --- /dev/null +++ b/dist/forms/reset-password-popup/index.scss @@ -0,0 +1,27 @@ +@import "~@edx/brand-edx.org/paragon/variables"; + +.separator { + border: 0 !important; + border-top: 0.075rem solid $light-500 !important; +} + +.back-to-login__button { + border-color: $primary-500 !important; + border: 2px solid !important; +} + +.loader-container { + height: 275px !important; +} + +.loader-heading { + color: $primary-500; +} + +#set-reset-password-form .pgn__form-control-floating-label-text:after { + content: none !important; +} + +.forgot-password-form__submit-btn__width { + min-width: 6rem; +} diff --git a/dist/forms/reset-password-popup/messages.js b/dist/forms/reset-password-popup/messages.js new file mode 100644 index 00000000..24c88590 --- /dev/null +++ b/dist/forms/reset-password-popup/messages.js @@ -0,0 +1,155 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; +const messages = defineMessages({ + resetPasswordFormHeading: { + id: 'reset.password.form.heading', + defaultMessage: 'Reset Password', + description: 'Reset password form main heading' + }, + resetPasswordFormSubmitButton: { + id: 'reset.password.form.submit.button', + defaultMessage: 'Submit', + description: 'Text for submit button on reset password form' + }, + resetPasswordFormNeedHelpText: { + id: 'reset.password.form.need.help.text', + defaultMessage: 'Need help signing in?', + description: 'reset Password help text' + }, + resetPasswordFormHelpCenterLink: { + id: 'reset.password.form.help.center.link', + defaultMessage: 'Help center', + description: 'Text for help center link' + }, + resetPasswordFormAdditionalHelpText: { + id: 'reset.password.form.additional.help.text', + defaultMessage: 'For additional help, contact edX support at', + description: 'Label for link that leads learners to the email page' + }, + resetPasswordBackToLoginButton: { + id: 'reset.password.back.to.login.button', + defaultMessage: 'Back to login', + description: 'Text for back to login button on reset password form' + }, + newPasswordLabel: { + id: 'new.password.label', + defaultMessage: 'New password', + description: 'New password field label for the reset password page.' + }, + confirmPasswordLabel: { + id: 'confirm.password.label', + defaultMessage: 'Confirm password', + description: 'Confirm password field label for the reset password page.' + }, + resetPasswordButton: { + id: 'reset.password.button', + defaultMessage: 'Reset password', + description: 'Button text for reset password popup.' + }, + enterConfirmPasswordMessage: { + id: 'enter.confirm.password.message', + defaultMessage: 'Enter and confirm the new password', + description: 'Message for entering and confirming the new password' + }, + // vulnerable password messages + vulnerablePasswordBlockedMessage: { + id: 'vulnerable.blocked.password.message', + defaultMessage: 'Our system detected critical password vulnerability. Please reset your password to keep your account secure.', + description: 'Message for blocking user to reset password due to vulnerable password' + }, + vulnerablePasswordWarnedMessage: { + id: 'vulnerable.warned.password.message', + defaultMessage: 'Our system detected password vulnerability. We encourage you to reset your password to keep your account secure.', + description: 'Message for warned user to reset password due to vulnerable password' + }, + // email sent messages + emailSentMessage: { + id: 'email.sent.message', + defaultMessage: 'Email has been sent', + description: 'Notification message indicating that an email has been sent' + }, + helpCenter: { + id: 'help.center', + defaultMessage: 'Help Center', + description: 'Part of reset password success message.' + }, + // validation errors + passwordRequiredMessage: { + id: 'password.required.message', + defaultMessage: 'Password is a required field', + description: 'Error message for empty password' + }, + passwordValidationMessage: { + id: 'password.validation.message', + defaultMessage: 'Password criteria has not been met', + description: 'Error message for invalid password' + }, + passwordDoNotMatch: { + id: 'passwords.do.not.match', + defaultMessage: 'Passwords do not match', + description: 'Password format error.' + }, + confirmYourPassword: { + id: 'confirm.your.password', + defaultMessage: 'Confirm your password', + description: 'Field validation message when confirm password is empty' + }, + // alert banner strings + resetPasswordFailureHeading: { + id: 'reset.password.failure.heading', + defaultMessage: 'We couldn\'t reset your password.', + description: 'Heading for reset password request failure' + }, + forgotPasswordFormEmailFieldLabel: { + id: 'forgot.Password.form.email.label', + defaultMessage: 'Email', + description: 'Label for email input field' + }, + forgotPasswordEmptyEmailFieldError: { + id: 'forgot.password.empty.email.field.error', + defaultMessage: 'Email is required', + description: 'Error message that appears when user tries to submit empty email field' + }, + forgotPasswordPageInvalidEmaiMessage: { + id: 'forgot.password.page.invalid.email.message', + defaultMessage: 'Enter a valid email address', + description: 'Invalid email address message for input field.' + }, + forgotPasswordInternalServerError: { + id: 'forgot.password.internal.server.error', + defaultMessage: 'An error has occurred. Try refreshing the page, or check your internet connection.', + description: 'Error message that appears when server responds with 500 error code' + }, + forgotPasswordErrorAlertTitle: { + id: 'forgot.password.error.alert.title.', + defaultMessage: 'We were unable to contact you.', + description: 'Failed to send password recovery email.' + }, + forgotPasswordExtendFieldErrors: { + id: 'forgot.password.extend.field.errors', + defaultMessage: '{emailError} below.', + description: 'extends the field error for alert message' + }, + forgotPasswordRequestInProgressMessage: { + id: 'forgot.password.request.in.progress.message', + defaultMessage: 'Your previous request is in progress, please try again in a few moments.', + description: 'Message displayed when previous password reset request is still in progress.' + }, + resetPasswordTokenValidatingHeadingText: { + id: 'reset.password.validate.token.heading.text', + defaultMessage: 'Validating your reset password link...', + description: 'Message displayed when token is being validated' + }, + // Reset password token validation failure + 'invalid.token.heading': { + id: 'invalid.token.heading', + defaultMessage: 'Invalid password reset link', + description: 'Alert heading when reset password link is invalid' + }, + 'invalid.token.error.message': { + id: 'invalid.token.error.message', + defaultMessage: 'This password reset link is invalid. It may have been used already. Enter your email below to receive a new link.', + description: 'Alert message when reset password link has expired or is invalid' + } +}); +export default messages; +//# sourceMappingURL=messages.js.map \ No newline at end of file diff --git a/dist/forms/reset-password-popup/messages.js.map b/dist/forms/reset-password-popup/messages.js.map new file mode 100644 index 00000000..4b0b7b43 --- /dev/null +++ b/dist/forms/reset-password-popup/messages.js.map @@ -0,0 +1 @@ +{"version":3,"file":"messages.js","names":["defineMessages","messages","resetPasswordFormHeading","id","defaultMessage","description","resetPasswordFormSubmitButton","resetPasswordFormNeedHelpText","resetPasswordFormHelpCenterLink","resetPasswordFormAdditionalHelpText","resetPasswordBackToLoginButton","newPasswordLabel","confirmPasswordLabel","resetPasswordButton","enterConfirmPasswordMessage","vulnerablePasswordBlockedMessage","vulnerablePasswordWarnedMessage","emailSentMessage","helpCenter","passwordRequiredMessage","passwordValidationMessage","passwordDoNotMatch","confirmYourPassword","resetPasswordFailureHeading","forgotPasswordFormEmailFieldLabel","forgotPasswordEmptyEmailFieldError","forgotPasswordPageInvalidEmaiMessage","forgotPasswordInternalServerError","forgotPasswordErrorAlertTitle","forgotPasswordExtendFieldErrors","forgotPasswordRequestInProgressMessage","resetPasswordTokenValidatingHeadingText"],"sources":["../../../src/forms/reset-password-popup/messages.js"],"sourcesContent":["import { defineMessages } from '@edx/frontend-platform/i18n';\n\nconst messages = defineMessages({\n resetPasswordFormHeading: {\n id: 'reset.password.form.heading',\n defaultMessage: 'Reset Password',\n description: 'Reset password form main heading',\n },\n resetPasswordFormSubmitButton: {\n id: 'reset.password.form.submit.button',\n defaultMessage: 'Submit',\n description: 'Text for submit button on reset password form',\n },\n resetPasswordFormNeedHelpText: {\n id: 'reset.password.form.need.help.text',\n defaultMessage: 'Need help signing in?',\n description: 'reset Password help text',\n },\n resetPasswordFormHelpCenterLink: {\n id: 'reset.password.form.help.center.link',\n defaultMessage: 'Help center',\n description: 'Text for help center link',\n },\n resetPasswordFormAdditionalHelpText: {\n id: 'reset.password.form.additional.help.text',\n defaultMessage: 'For additional help, contact edX support at',\n description: 'Label for link that leads learners to the email page',\n },\n resetPasswordBackToLoginButton: {\n id: 'reset.password.back.to.login.button',\n defaultMessage: 'Back to login',\n description: 'Text for back to login button on reset password form',\n },\n newPasswordLabel: {\n id: 'new.password.label',\n defaultMessage: 'New password',\n description: 'New password field label for the reset password page.',\n },\n confirmPasswordLabel: {\n id: 'confirm.password.label',\n defaultMessage: 'Confirm password',\n description: 'Confirm password field label for the reset password page.',\n },\n resetPasswordButton: {\n id: 'reset.password.button',\n defaultMessage: 'Reset password',\n description: 'Button text for reset password popup.',\n },\n enterConfirmPasswordMessage: {\n id: 'enter.confirm.password.message',\n defaultMessage: 'Enter and confirm the new password',\n description: 'Message for entering and confirming the new password',\n },\n // vulnerable password messages\n vulnerablePasswordBlockedMessage: {\n id: 'vulnerable.blocked.password.message',\n defaultMessage: 'Our system detected critical password vulnerability. Please reset your password to keep your account secure.',\n description: 'Message for blocking user to reset password due to vulnerable password',\n },\n vulnerablePasswordWarnedMessage: {\n id: 'vulnerable.warned.password.message',\n defaultMessage: 'Our system detected password vulnerability. We encourage you to reset your password to keep your account secure.',\n description: 'Message for warned user to reset password due to vulnerable password',\n },\n // email sent messages\n emailSentMessage: {\n id: 'email.sent.message',\n defaultMessage: 'Email has been sent',\n description: 'Notification message indicating that an email has been sent',\n },\n helpCenter: {\n id: 'help.center',\n defaultMessage: 'Help Center',\n description: 'Part of reset password success message.',\n },\n // validation errors\n passwordRequiredMessage: {\n id: 'password.required.message',\n defaultMessage: 'Password is a required field',\n description: 'Error message for empty password',\n },\n passwordValidationMessage: {\n id: 'password.validation.message',\n defaultMessage: 'Password criteria has not been met',\n description: 'Error message for invalid password',\n },\n passwordDoNotMatch: {\n id: 'passwords.do.not.match',\n defaultMessage: 'Passwords do not match',\n description: 'Password format error.',\n },\n confirmYourPassword: {\n id: 'confirm.your.password',\n defaultMessage: 'Confirm your password',\n description: 'Field validation message when confirm password is empty',\n },\n // alert banner strings\n resetPasswordFailureHeading: {\n id: 'reset.password.failure.heading',\n defaultMessage: 'We couldn\\'t reset your password.',\n description: 'Heading for reset password request failure',\n },\n forgotPasswordFormEmailFieldLabel: {\n id: 'forgot.Password.form.email.label',\n defaultMessage: 'Email',\n description: 'Label for email input field',\n },\n forgotPasswordEmptyEmailFieldError: {\n id: 'forgot.password.empty.email.field.error',\n defaultMessage: 'Email is required',\n description: 'Error message that appears when user tries to submit empty email field',\n },\n forgotPasswordPageInvalidEmaiMessage: {\n id: 'forgot.password.page.invalid.email.message',\n defaultMessage: 'Enter a valid email address',\n description: 'Invalid email address message for input field.',\n },\n forgotPasswordInternalServerError: {\n id: 'forgot.password.internal.server.error',\n defaultMessage: 'An error has occurred. Try refreshing the page, or check your internet connection.',\n description: 'Error message that appears when server responds with 500 error code',\n },\n forgotPasswordErrorAlertTitle: {\n id: 'forgot.password.error.alert.title.',\n defaultMessage: 'We were unable to contact you.',\n description: 'Failed to send password recovery email.',\n },\n forgotPasswordExtendFieldErrors: {\n id: 'forgot.password.extend.field.errors',\n defaultMessage: '{emailError} below.',\n description: 'extends the field error for alert message',\n },\n forgotPasswordRequestInProgressMessage: {\n id: 'forgot.password.request.in.progress.message',\n defaultMessage: 'Your previous request is in progress, please try again in a few moments.',\n description: 'Message displayed when previous password reset request is still in progress.',\n },\n resetPasswordTokenValidatingHeadingText: {\n id: 'reset.password.validate.token.heading.text',\n defaultMessage: 'Validating your reset password link...',\n description: 'Message displayed when token is being validated',\n },\n // Reset password token validation failure\n 'invalid.token.heading': {\n id: 'invalid.token.heading',\n defaultMessage: 'Invalid password reset link',\n description: 'Alert heading when reset password link is invalid',\n },\n 'invalid.token.error.message': {\n id: 'invalid.token.error.message',\n defaultMessage: 'This password reset link is invalid. It may have been used already. Enter your email below to receive a new link.',\n description: 'Alert message when reset password link has expired or is invalid',\n },\n});\n\nexport default messages;\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/reset-password-popup/reset-password/components/ResetPasswordFailure.js b/dist/forms/reset-password-popup/reset-password/components/ResetPasswordFailure.js new file mode 100644 index 00000000..d9aed273 --- /dev/null +++ b/dist/forms/reset-password-popup/reset-password/components/ResetPasswordFailure.js @@ -0,0 +1,51 @@ +import React from 'react'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Alert } from '@openedx/paragon'; +import PropTypes from 'prop-types'; +import { FORM_SUBMISSION_ERROR } from '../../../../data/constants'; +import { PASSWORD_RESET, PASSWORD_VALIDATION_ERROR } from '../data/constants'; +import messages from '../messages'; +const ResetPasswordFailure = props => { + const { + formatMessage + } = useIntl(); + const { + errorCode, + errorMsg + } = props; + let errorMessage = null; + switch (errorCode) { + case PASSWORD_RESET.FORBIDDEN_REQUEST: + errorMessage = formatMessage(messages.rateLimitError); + break; + case PASSWORD_RESET.INTERNAL_SERVER_ERROR: + errorMessage = formatMessage(messages.internalServerError); + break; + case PASSWORD_VALIDATION_ERROR: + errorMessage = errorMsg; + break; + case FORM_SUBMISSION_ERROR: + errorMessage = formatMessage(messages.resetPasswordFormSubmissionError); + break; + default: + break; + } + if (errorMessage) { + return /*#__PURE__*/React.createElement(Alert, { + id: "validation-errors", + className: "mb-4", + variant: "danger" + }, /*#__PURE__*/React.createElement("p", null, errorMessage)); + } + return null; +}; +ResetPasswordFailure.defaultProps = { + errorCode: null, + errorMsg: null +}; +ResetPasswordFailure.propTypes = { + errorCode: PropTypes.string, + errorMsg: PropTypes.string +}; +export default ResetPasswordFailure; +//# sourceMappingURL=ResetPasswordFailure.js.map \ No newline at end of file diff --git a/dist/forms/reset-password-popup/reset-password/components/ResetPasswordFailure.js.map b/dist/forms/reset-password-popup/reset-password/components/ResetPasswordFailure.js.map new file mode 100644 index 00000000..209e4dbf --- /dev/null +++ b/dist/forms/reset-password-popup/reset-password/components/ResetPasswordFailure.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ResetPasswordFailure.js","names":["React","useIntl","Alert","PropTypes","FORM_SUBMISSION_ERROR","PASSWORD_RESET","PASSWORD_VALIDATION_ERROR","messages","ResetPasswordFailure","props","formatMessage","errorCode","errorMsg","errorMessage","FORBIDDEN_REQUEST","rateLimitError","INTERNAL_SERVER_ERROR","internalServerError","resetPasswordFormSubmissionError","createElement","id","className","variant","defaultProps","propTypes","string"],"sources":["../../../../../src/forms/reset-password-popup/reset-password/components/ResetPasswordFailure.jsx"],"sourcesContent":["import React from 'react';\n\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport { Alert } from '@openedx/paragon';\nimport PropTypes from 'prop-types';\n\nimport { FORM_SUBMISSION_ERROR } from '../../../../data/constants';\nimport { PASSWORD_RESET, PASSWORD_VALIDATION_ERROR } from '../data/constants';\nimport messages from '../messages';\n\nconst ResetPasswordFailure = (props) => {\n const { formatMessage } = useIntl();\n const { errorCode, errorMsg } = props;\n\n let errorMessage = null;\n switch (errorCode) {\n case PASSWORD_RESET.FORBIDDEN_REQUEST:\n errorMessage = formatMessage(messages.rateLimitError);\n break;\n case PASSWORD_RESET.INTERNAL_SERVER_ERROR:\n errorMessage = formatMessage(messages.internalServerError);\n break;\n case PASSWORD_VALIDATION_ERROR:\n errorMessage = errorMsg;\n break;\n case FORM_SUBMISSION_ERROR:\n errorMessage = formatMessage(messages.resetPasswordFormSubmissionError);\n break;\n default:\n break;\n }\n\n if (errorMessage) {\n return (\n \n

{errorMessage}

\n
\n );\n }\n\n return null;\n};\n\nResetPasswordFailure.defaultProps = {\n errorCode: null,\n errorMsg: null,\n};\n\nResetPasswordFailure.propTypes = {\n errorCode: PropTypes.string,\n errorMsg: PropTypes.string,\n};\n\nexport default ResetPasswordFailure;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AAEzB,SAASC,OAAO,QAAQ,6BAA6B;AACrD,SAASC,KAAK,QAAQ,kBAAkB;AACxC,OAAOC,SAAS,MAAM,YAAY;AAElC,SAASC,qBAAqB,QAAQ,4BAA4B;AAClE,SAASC,cAAc,EAAEC,yBAAyB,QAAQ,mBAAmB;AAC7E,OAAOC,QAAQ,MAAM,aAAa;AAElC,MAAMC,oBAAoB,GAAIC,KAAK,IAAK;EACtC,MAAM;IAAEC;EAAc,CAAC,GAAGT,OAAO,CAAC,CAAC;EACnC,MAAM;IAAEU,SAAS;IAAEC;EAAS,CAAC,GAAGH,KAAK;EAErC,IAAII,YAAY,GAAG,IAAI;EACvB,QAAQF,SAAS;IACf,KAAKN,cAAc,CAACS,iBAAiB;MACnCD,YAAY,GAAGH,aAAa,CAACH,QAAQ,CAACQ,cAAc,CAAC;MACrD;IACF,KAAKV,cAAc,CAACW,qBAAqB;MACvCH,YAAY,GAAGH,aAAa,CAACH,QAAQ,CAACU,mBAAmB,CAAC;MAC1D;IACF,KAAKX,yBAAyB;MAC5BO,YAAY,GAAGD,QAAQ;MACxB;IACD,KAAKR,qBAAqB;MACxBS,YAAY,GAAGH,aAAa,CAACH,QAAQ,CAACW,gCAAgC,CAAC;MACvE;IACF;MACE;EACJ;EAEA,IAAIL,YAAY,EAAE;IAChB,oBACEb,KAAA,CAAAmB,aAAA,CAACjB,KAAK;MAACkB,EAAE,EAAC,mBAAmB;MAACC,SAAS,EAAC,MAAM;MAACC,OAAO,EAAC;IAAQ,gBAC7DtB,KAAA,CAAAmB,aAAA,YAAIN,YAAgB,CACf,CAAC;EAEZ;EAEA,OAAO,IAAI;AACb,CAAC;AAEDL,oBAAoB,CAACe,YAAY,GAAG;EAClCZ,SAAS,EAAE,IAAI;EACfC,QAAQ,EAAE;AACZ,CAAC;AAEDJ,oBAAoB,CAACgB,SAAS,GAAG;EAC/Bb,SAAS,EAAER,SAAS,CAACsB,MAAM;EAC3Bb,QAAQ,EAAET,SAAS,CAACsB;AACtB,CAAC;AAED,eAAejB,oBAAoB","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/reset-password-popup/reset-password/components/ResetPasswordSuccess.js b/dist/forms/reset-password-popup/reset-password/components/ResetPasswordSuccess.js new file mode 100644 index 00000000..d0fc76fa --- /dev/null +++ b/dist/forms/reset-password-popup/reset-password/components/ResetPasswordSuccess.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Alert } from '@openedx/paragon'; +import messages from '../messages'; +const ResetPasswordSuccess = () => { + const { + formatMessage + } = useIntl(); + return /*#__PURE__*/React.createElement(Alert, { + id: "reset-password-success", + variant: "success", + className: "mb-5" + }, /*#__PURE__*/React.createElement("p", null, formatMessage(messages.resetPassowrdSuccess))); +}; +export default ResetPasswordSuccess; +//# sourceMappingURL=ResetPasswordSuccess.js.map \ No newline at end of file diff --git a/dist/forms/reset-password-popup/reset-password/components/ResetPasswordSuccess.js.map b/dist/forms/reset-password-popup/reset-password/components/ResetPasswordSuccess.js.map new file mode 100644 index 00000000..6edc11c1 --- /dev/null +++ b/dist/forms/reset-password-popup/reset-password/components/ResetPasswordSuccess.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ResetPasswordSuccess.js","names":["React","useIntl","Alert","messages","ResetPasswordSuccess","formatMessage","createElement","id","variant","className","resetPassowrdSuccess"],"sources":["../../../../../src/forms/reset-password-popup/reset-password/components/ResetPasswordSuccess.jsx"],"sourcesContent":["import React from 'react';\n\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport { Alert } from '@openedx/paragon';\n\nimport messages from '../messages';\n\nconst ResetPasswordSuccess = () => {\n const { formatMessage } = useIntl();\n\n return (\n \n

{formatMessage(messages.resetPassowrdSuccess)}

\n
\n );\n};\n\nexport default ResetPasswordSuccess;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AAEzB,SAASC,OAAO,QAAQ,6BAA6B;AACrD,SAASC,KAAK,QAAQ,kBAAkB;AAExC,OAAOC,QAAQ,MAAM,aAAa;AAElC,MAAMC,oBAAoB,GAAGA,CAAA,KAAM;EACjC,MAAM;IAAEC;EAAc,CAAC,GAAGJ,OAAO,CAAC,CAAC;EAEnC,oBACED,KAAA,CAAAM,aAAA,CAACJ,KAAK;IAACK,EAAE,EAAC,wBAAwB;IAACC,OAAO,EAAC,SAAS;IAACC,SAAS,EAAC;EAAM,gBACnET,KAAA,CAAAM,aAAA,YAAID,aAAa,CAACF,QAAQ,CAACO,oBAAoB,CAAK,CAC/C,CAAC;AAEZ,CAAC;AAED,eAAeN,oBAAoB","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/reset-password-popup/reset-password/data/constants.js b/dist/forms/reset-password-popup/reset-password/data/constants.js new file mode 100644 index 00000000..e8075adf --- /dev/null +++ b/dist/forms/reset-password-popup/reset-password/data/constants.js @@ -0,0 +1,15 @@ +export const TOKEN_STATE = { + PENDING: 'token-pending', + VALID: 'token-valid' +}; + +// password reset error codes +export const PASSWORD_RESET_ERROR = 'password-reset-error'; +export const SUCCESS = 'success'; +export const PASSWORD_VALIDATION_ERROR = 'password-validation-failure'; +export const PASSWORD_RESET = { + INVALID_TOKEN: 'invalid-token', + INTERNAL_SERVER_ERROR: 'password-reset-internal-server-error', + FORBIDDEN_REQUEST: 'password-reset-rate-limit-error' +}; +//# sourceMappingURL=constants.js.map \ No newline at end of file diff --git a/dist/forms/reset-password-popup/reset-password/data/constants.js.map b/dist/forms/reset-password-popup/reset-password/data/constants.js.map new file mode 100644 index 00000000..fd1fc847 --- /dev/null +++ b/dist/forms/reset-password-popup/reset-password/data/constants.js.map @@ -0,0 +1 @@ +{"version":3,"file":"constants.js","names":["TOKEN_STATE","PENDING","VALID","PASSWORD_RESET_ERROR","SUCCESS","PASSWORD_VALIDATION_ERROR","PASSWORD_RESET","INVALID_TOKEN","INTERNAL_SERVER_ERROR","FORBIDDEN_REQUEST"],"sources":["../../../../../src/forms/reset-password-popup/reset-password/data/constants.js"],"sourcesContent":["export const TOKEN_STATE = {\n PENDING: 'token-pending',\n VALID: 'token-valid',\n};\n\n// password reset error codes\nexport const PASSWORD_RESET_ERROR = 'password-reset-error';\nexport const SUCCESS = 'success';\nexport const PASSWORD_VALIDATION_ERROR = 'password-validation-failure';\n\nexport const PASSWORD_RESET = {\n INVALID_TOKEN: 'invalid-token',\n INTERNAL_SERVER_ERROR: 'password-reset-internal-server-error',\n FORBIDDEN_REQUEST: 'password-reset-rate-limit-error',\n};\n"],"mappings":"AAAA,OAAO,MAAMA,WAAW,GAAG;EACzBC,OAAO,EAAE,eAAe;EACxBC,KAAK,EAAE;AACT,CAAC;;AAED;AACA,OAAO,MAAMC,oBAAoB,GAAG,sBAAsB;AAC1D,OAAO,MAAMC,OAAO,GAAG,SAAS;AAChC,OAAO,MAAMC,yBAAyB,GAAG,6BAA6B;AAEtE,OAAO,MAAMC,cAAc,GAAG;EAC5BC,aAAa,EAAE,eAAe;EAC9BC,qBAAqB,EAAE,sCAAsC;EAC7DC,iBAAiB,EAAE;AACrB,CAAC","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/reset-password-popup/reset-password/data/reducers.js b/dist/forms/reset-password-popup/reset-password/data/reducers.js new file mode 100644 index 00000000..1cceff22 --- /dev/null +++ b/dist/forms/reset-password-popup/reset-password/data/reducers.js @@ -0,0 +1,87 @@ +/** + * Redux slice for managing registration state. + * This slice handles the registration process, including the submission state, + * registration result, and any registration errors. + */ + +import { createSlice } from '@reduxjs/toolkit'; +import { PASSWORD_RESET_ERROR, SUCCESS, TOKEN_STATE } from './constants'; +import { COMPLETE_STATE, DEFAULT_STATE, FAILURE_STATE, PENDING_STATE } from '../../../../data/constants'; +export const storeName = 'resetPassword'; +export const REGISTER_SLICE_NAME = 'resetPassword'; +export const resetPasswordInitialState = { + tokenValidationState: DEFAULT_STATE, + resetPasswordsubmitState: DEFAULT_STATE, + status: TOKEN_STATE.PENDING, + token: null, + errorMsg: null, + tokenError: null, + backendValidationError: null +}; +export const resetPasswordSlice = createSlice({ + name: REGISTER_SLICE_NAME, + initialState: resetPasswordInitialState, + reducers: { + validateToken: state => { + state.tokenValidationState = PENDING_STATE; + state.status = PENDING_STATE; + }, + validateTokenSuccess: (state, _ref) => { + let { + payload + } = _ref; + state.tokenValidationState = COMPLETE_STATE; + state.status = TOKEN_STATE.VALID; + state.token = payload; + }, + validateTokenFailed: (state, _ref2) => { + let { + payload + } = _ref2; + state.status = PASSWORD_RESET_ERROR; + state.tokenValidationState = DEFAULT_STATE; + state.tokenError = payload; + }, + resetPassword: state => { + state.status = PENDING_STATE; + state.resetPasswordsubmitState = PENDING_STATE; + }, + resetPasswordSuccess: state => { + state.status = SUCCESS; + state.resetPasswordsubmitState = COMPLETE_STATE; + }, + resetPasswordFailure: (state, _ref3) => { + let { + payload + } = _ref3; + state.status = payload.status; + state.resetPasswordsubmitState = FAILURE_STATE; + state.errorMsg = payload.errorMsg; + }, + validatePassword: state => { + state.backendValidationError = null; + }, + validatePasswordSuccess: (state, _ref4) => { + let { + payload + } = _ref4; + state.backendValidationError = payload; + }, + validatePasswordFailure: state => { + state.backendValidationError = null; + } + } +}); +export const { + validateToken, + validatePassword, + validateTokenSuccess, + validateTokenFailed, + resetPassword, + resetPasswordSuccess, + resetPasswordFailure, + validatePasswordSuccess, + validatePasswordFailure +} = resetPasswordSlice.actions; +export default resetPasswordSlice.reducer; +//# sourceMappingURL=reducers.js.map \ No newline at end of file diff --git a/dist/forms/reset-password-popup/reset-password/data/reducers.js.map b/dist/forms/reset-password-popup/reset-password/data/reducers.js.map new file mode 100644 index 00000000..bc0dc2b1 --- /dev/null +++ b/dist/forms/reset-password-popup/reset-password/data/reducers.js.map @@ -0,0 +1 @@ +{"version":3,"file":"reducers.js","names":["createSlice","PASSWORD_RESET_ERROR","SUCCESS","TOKEN_STATE","COMPLETE_STATE","DEFAULT_STATE","FAILURE_STATE","PENDING_STATE","storeName","REGISTER_SLICE_NAME","resetPasswordInitialState","tokenValidationState","resetPasswordsubmitState","status","PENDING","token","errorMsg","tokenError","backendValidationError","resetPasswordSlice","name","initialState","reducers","validateToken","state","validateTokenSuccess","_ref","payload","VALID","validateTokenFailed","_ref2","resetPassword","resetPasswordSuccess","resetPasswordFailure","_ref3","validatePassword","validatePasswordSuccess","_ref4","validatePasswordFailure","actions","reducer"],"sources":["../../../../../src/forms/reset-password-popup/reset-password/data/reducers.js"],"sourcesContent":["/**\n * Redux slice for managing registration state.\n * This slice handles the registration process, including the submission state,\n * registration result, and any registration errors.\n */\n\nimport { createSlice } from '@reduxjs/toolkit';\n\nimport { PASSWORD_RESET_ERROR, SUCCESS, TOKEN_STATE } from './constants';\nimport {\n COMPLETE_STATE, DEFAULT_STATE, FAILURE_STATE, PENDING_STATE,\n} from '../../../../data/constants';\n\nexport const storeName = 'resetPassword';\nexport const REGISTER_SLICE_NAME = 'resetPassword';\n\nexport const resetPasswordInitialState = {\n tokenValidationState: DEFAULT_STATE,\n resetPasswordsubmitState: DEFAULT_STATE,\n status: TOKEN_STATE.PENDING,\n token: null,\n errorMsg: null,\n tokenError: null,\n backendValidationError: null,\n};\n\nexport const resetPasswordSlice = createSlice({\n name: REGISTER_SLICE_NAME,\n initialState: resetPasswordInitialState,\n reducers: {\n validateToken: (state) => {\n state.tokenValidationState = PENDING_STATE;\n state.status = PENDING_STATE;\n },\n validateTokenSuccess: (state, { payload }) => {\n state.tokenValidationState = COMPLETE_STATE;\n state.status = TOKEN_STATE.VALID;\n state.token = payload;\n },\n validateTokenFailed: (state, { payload }) => {\n state.status = PASSWORD_RESET_ERROR;\n state.tokenValidationState = DEFAULT_STATE;\n state.tokenError = payload;\n },\n resetPassword: (state) => {\n state.status = PENDING_STATE;\n state.resetPasswordsubmitState = PENDING_STATE;\n },\n resetPasswordSuccess: (state) => {\n state.status = SUCCESS;\n state.resetPasswordsubmitState = COMPLETE_STATE;\n },\n resetPasswordFailure: (state, { payload }) => {\n state.status = payload.status;\n state.resetPasswordsubmitState = FAILURE_STATE;\n state.errorMsg = payload.errorMsg;\n },\n validatePassword: (state) => {\n state.backendValidationError = null;\n },\n validatePasswordSuccess: (state, { payload }) => {\n state.backendValidationError = payload;\n },\n validatePasswordFailure: (state) => {\n state.backendValidationError = null;\n },\n },\n});\n\nexport const {\n validateToken,\n validatePassword,\n validateTokenSuccess,\n validateTokenFailed,\n resetPassword,\n resetPasswordSuccess,\n resetPasswordFailure,\n validatePasswordSuccess,\n validatePasswordFailure,\n} = resetPasswordSlice.actions;\n\nexport default resetPasswordSlice.reducer;\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/reset-password-popup/reset-password/data/sagas.js b/dist/forms/reset-password-popup/reset-password/data/sagas.js new file mode 100644 index 00000000..6b99201e --- /dev/null +++ b/dist/forms/reset-password-popup/reset-password/data/sagas.js @@ -0,0 +1,79 @@ +import { logError, logInfo } from '@edx/frontend-platform/logging'; +import { call, put, takeEvery } from 'redux-saga/effects'; +import { PASSWORD_RESET, PASSWORD_VALIDATION_ERROR } from './constants'; +import { resetPassword, resetPasswordFailure, resetPasswordSuccess, validatePassword, validatePasswordFailure, validatePasswordSuccess, validateToken, validateTokenFailed, validateTokenSuccess } from './reducers'; +import { resetPasswordRequest, validatePasswordRequest, validateTokenRequest } from './service'; +import { setShowPasswordResetBanner } from '../../../login-popup/data/reducers'; +import { forgotPassweordTokenInvalidFailure } from '../../forgot-password/data/reducers'; + +// Services +export function* handleValidateToken(action) { + try { + const data = yield call(validateTokenRequest, action.payload); + const isValid = data.is_valid; + if (isValid) { + yield put(validateTokenSuccess(isValid, action.payload)); + } else { + yield put(validateTokenFailed(PASSWORD_RESET.INVALID_TOKEN)); + yield put(forgotPassweordTokenInvalidFailure(PASSWORD_RESET.INVALID_TOKEN)); + } + } catch (err) { + if (err.response && err.response.status === 429) { + yield put(validateTokenFailed(PASSWORD_RESET.FORBIDDEN_REQUEST)); + yield put(forgotPassweordTokenInvalidFailure(PASSWORD_RESET.FORBIDDEN_REQUEST)); + logInfo(err); + } else { + yield put(validateTokenFailed(PASSWORD_RESET.INTERNAL_SERVER_ERROR)); + yield put(forgotPassweordTokenInvalidFailure(PASSWORD_RESET.INTERNAL_SERVER_ERROR)); + logError(err); + } + } +} +export function* handleValidatePassword(action) { + try { + const data = yield call(validatePasswordRequest, action.payload); + yield put(validatePasswordSuccess(data)); + } catch (err) { + yield put(validatePasswordFailure()); + logError(err); + } +} +export function* handleResetPassword(action) { + try { + const data = yield call(resetPasswordRequest, action.payload.formPayload, action.payload.token, action.payload.params); + const resetStatus = data.reset_status; + const resetErrors = data.err_msg; + if (resetStatus) { + yield put(resetPasswordSuccess(resetStatus)); + yield put(setShowPasswordResetBanner()); + } else if (data.token_invalid) { + yield put(resetPasswordFailure({ + status: PASSWORD_RESET.INVALID_TOKEN + })); + yield put(forgotPassweordTokenInvalidFailure(PASSWORD_RESET.INVALID_TOKEN)); + } else { + yield put(resetPasswordFailure({ + status: PASSWORD_VALIDATION_ERROR, + errorMsg: resetErrors + })); + } + } catch (err) { + if (err.response && err.response.status === 429) { + yield put(resetPasswordFailure({ + status: PASSWORD_RESET.FORBIDDEN_REQUEST + })); + logInfo(err); + } else { + yield put(resetPasswordFailure({ + status: PASSWORD_RESET.INTERNAL_SERVER_ERROR + })); + logError(err); + } + } +} +export default function* saga() { + yield takeEvery(resetPassword.type, handleResetPassword); + yield takeEvery(validateToken.type, handleValidateToken); + yield takeEvery(validatePassword.type, handleValidatePassword); +} +//# sourceMappingURL=sagas.js.map \ No newline at end of file diff --git a/dist/forms/reset-password-popup/reset-password/data/sagas.js.map b/dist/forms/reset-password-popup/reset-password/data/sagas.js.map new file mode 100644 index 00000000..2f4dd0b4 --- /dev/null +++ b/dist/forms/reset-password-popup/reset-password/data/sagas.js.map @@ -0,0 +1 @@ +{"version":3,"file":"sagas.js","names":["logError","logInfo","call","put","takeEvery","PASSWORD_RESET","PASSWORD_VALIDATION_ERROR","resetPassword","resetPasswordFailure","resetPasswordSuccess","validatePassword","validatePasswordFailure","validatePasswordSuccess","validateToken","validateTokenFailed","validateTokenSuccess","resetPasswordRequest","validatePasswordRequest","validateTokenRequest","setShowPasswordResetBanner","forgotPassweordTokenInvalidFailure","handleValidateToken","action","data","payload","isValid","is_valid","INVALID_TOKEN","err","response","status","FORBIDDEN_REQUEST","INTERNAL_SERVER_ERROR","handleValidatePassword","handleResetPassword","formPayload","token","params","resetStatus","reset_status","resetErrors","err_msg","token_invalid","errorMsg","saga","type"],"sources":["../../../../../src/forms/reset-password-popup/reset-password/data/sagas.js"],"sourcesContent":["import { logError, logInfo } from '@edx/frontend-platform/logging';\nimport { call, put, takeEvery } from 'redux-saga/effects';\n\nimport { PASSWORD_RESET, PASSWORD_VALIDATION_ERROR } from './constants';\nimport {\n resetPassword,\n resetPasswordFailure,\n resetPasswordSuccess,\n validatePassword,\n validatePasswordFailure,\n validatePasswordSuccess,\n validateToken,\n validateTokenFailed,\n validateTokenSuccess,\n} from './reducers';\nimport { resetPasswordRequest, validatePasswordRequest, validateTokenRequest } from './service';\nimport { setShowPasswordResetBanner } from '../../../login-popup/data/reducers';\nimport { forgotPassweordTokenInvalidFailure } from '../../forgot-password/data/reducers';\n\n// Services\nexport function* handleValidateToken(action) {\n try {\n const data = yield call(validateTokenRequest, action.payload);\n const isValid = data.is_valid;\n\n if (isValid) {\n yield put(validateTokenSuccess(isValid, action.payload));\n } else {\n yield put(validateTokenFailed(PASSWORD_RESET.INVALID_TOKEN));\n yield put(forgotPassweordTokenInvalidFailure(PASSWORD_RESET.INVALID_TOKEN));\n }\n } catch (err) {\n if (err.response && err.response.status === 429) {\n yield put(validateTokenFailed(PASSWORD_RESET.FORBIDDEN_REQUEST));\n yield put(forgotPassweordTokenInvalidFailure(PASSWORD_RESET.FORBIDDEN_REQUEST));\n logInfo(err);\n } else {\n yield put(validateTokenFailed(PASSWORD_RESET.INTERNAL_SERVER_ERROR));\n yield put(forgotPassweordTokenInvalidFailure(PASSWORD_RESET.INTERNAL_SERVER_ERROR));\n logError(err);\n }\n }\n}\n\nexport function* handleValidatePassword(action) {\n try {\n const data = yield call(validatePasswordRequest, action.payload);\n yield put(validatePasswordSuccess(data));\n } catch (err) {\n yield put(validatePasswordFailure());\n logError(err);\n }\n}\n\nexport function* handleResetPassword(action) {\n try {\n const data = yield call(\n resetPasswordRequest,\n action.payload.formPayload,\n action.payload.token,\n action.payload.params,\n );\n const resetStatus = data.reset_status;\n const resetErrors = data.err_msg;\n\n if (resetStatus) {\n yield put(resetPasswordSuccess(resetStatus));\n yield put(setShowPasswordResetBanner());\n } else if (data.token_invalid) {\n yield put(resetPasswordFailure({\n status: PASSWORD_RESET.INVALID_TOKEN,\n }));\n yield put(forgotPassweordTokenInvalidFailure(PASSWORD_RESET.INVALID_TOKEN));\n } else {\n yield put(resetPasswordFailure({\n status: PASSWORD_VALIDATION_ERROR,\n errorMsg: resetErrors,\n }));\n }\n } catch (err) {\n if (err.response && err.response.status === 429) {\n yield put(resetPasswordFailure({\n status: PASSWORD_RESET.FORBIDDEN_REQUEST,\n }));\n logInfo(err);\n } else {\n yield put(resetPasswordFailure({\n status: PASSWORD_RESET.INTERNAL_SERVER_ERROR,\n }));\n logError(err);\n }\n }\n}\n\nexport default function* saga() {\n yield takeEvery(resetPassword.type, handleResetPassword);\n yield takeEvery(validateToken.type, handleValidateToken);\n yield takeEvery(validatePassword.type, handleValidatePassword);\n}\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/reset-password-popup/reset-password/data/service.js b/dist/forms/reset-password-popup/reset-password/data/service.js new file mode 100644 index 00000000..8a712450 --- /dev/null +++ b/dist/forms/reset-password-popup/reset-password/data/service.js @@ -0,0 +1,55 @@ +import { getConfig } from '@edx/frontend-platform'; +import { getHttpClient } from '@edx/frontend-platform/auth'; +import formurlencoded from 'form-urlencoded'; +export async function validateTokenRequest(token) { + const requestConfig = { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }; + const { + data + } = await getHttpClient().post(`${getConfig().LMS_BASE_URL}/user_api/v1/account/password_reset/token/validate/`, formurlencoded({ + token + }), requestConfig).catch(e => { + throw e; + }); + return data; +} +export async function resetPasswordRequest(payload, token, queryParams) { + const requestConfig = { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }; + const url = new URL(`${getConfig().LMS_BASE_URL}/password/reset/${token}/`); + if (queryParams.is_account_recovery) { + url.searchParams.append('is_account_recovery', true); + } + const { + data + } = await getHttpClient().post(url.href, formurlencoded(payload), requestConfig).catch(e => { + throw e; + }); + return data; +} +export async function validatePasswordRequest(payload) { + const requestConfig = { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }; + const { + data + } = await getHttpClient().post(`${getConfig().LMS_BASE_URL}/api/user/v1/validation/registration`, formurlencoded(payload), requestConfig).catch(e => { + throw e; + }); + let errorMessage = ''; + // Be careful about grabbing this message, since we could have received an HTTP error or the + // endpoint didn't give us what we expect. We only care if we get a clear error message. + if (data.validation_decisions && data.validation_decisions.password) { + errorMessage = data.validation_decisions.password; + } + return errorMessage; +} +//# sourceMappingURL=service.js.map \ No newline at end of file diff --git a/dist/forms/reset-password-popup/reset-password/data/service.js.map b/dist/forms/reset-password-popup/reset-password/data/service.js.map new file mode 100644 index 00000000..77dbb47a --- /dev/null +++ b/dist/forms/reset-password-popup/reset-password/data/service.js.map @@ -0,0 +1 @@ +{"version":3,"file":"service.js","names":["getConfig","getHttpClient","formurlencoded","validateTokenRequest","token","requestConfig","headers","data","post","LMS_BASE_URL","catch","e","resetPasswordRequest","payload","queryParams","url","URL","is_account_recovery","searchParams","append","href","validatePasswordRequest","errorMessage","validation_decisions","password"],"sources":["../../../../../src/forms/reset-password-popup/reset-password/data/service.js"],"sourcesContent":["import { getConfig } from '@edx/frontend-platform';\nimport { getHttpClient } from '@edx/frontend-platform/auth';\nimport formurlencoded from 'form-urlencoded';\n\nexport async function validateTokenRequest(token) {\n const requestConfig = {\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n };\n\n const { data } = await getHttpClient()\n .post(\n `${getConfig().LMS_BASE_URL}/user_api/v1/account/password_reset/token/validate/`,\n formurlencoded({ token }),\n requestConfig,\n )\n .catch((e) => {\n throw (e);\n });\n return data;\n}\n\nexport async function resetPasswordRequest(payload, token, queryParams) {\n const requestConfig = {\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n };\n const url = new URL(`${getConfig().LMS_BASE_URL}/password/reset/${token}/`);\n\n if (queryParams.is_account_recovery) {\n url.searchParams.append('is_account_recovery', true);\n }\n\n const { data } = await getHttpClient()\n .post(url.href, formurlencoded(payload), requestConfig)\n .catch((e) => {\n throw (e);\n });\n return data;\n}\n\nexport async function validatePasswordRequest(payload) {\n const requestConfig = {\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n };\n const { data } = await getHttpClient()\n .post(\n `${getConfig().LMS_BASE_URL}/api/user/v1/validation/registration`,\n formurlencoded(payload),\n requestConfig,\n )\n .catch((e) => {\n throw (e);\n });\n\n let errorMessage = '';\n // Be careful about grabbing this message, since we could have received an HTTP error or the\n // endpoint didn't give us what we expect. We only care if we get a clear error message.\n if (data.validation_decisions && data.validation_decisions.password) {\n errorMessage = data.validation_decisions.password;\n }\n\n return errorMessage;\n}\n"],"mappings":"AAAA,SAASA,SAAS,QAAQ,wBAAwB;AAClD,SAASC,aAAa,QAAQ,6BAA6B;AAC3D,OAAOC,cAAc,MAAM,iBAAiB;AAE5C,OAAO,eAAeC,oBAAoBA,CAACC,KAAK,EAAE;EAChD,MAAMC,aAAa,GAAG;IACpBC,OAAO,EAAE;MAAE,cAAc,EAAE;IAAoC;EACjE,CAAC;EAED,MAAM;IAAEC;EAAK,CAAC,GAAG,MAAMN,aAAa,CAAC,CAAC,CACnCO,IAAI,CACF,GAAER,SAAS,CAAC,CAAC,CAACS,YAAa,qDAAoD,EAChFP,cAAc,CAAC;IAAEE;EAAM,CAAC,CAAC,EACzBC,aACF,CAAC,CACAK,KAAK,CAAEC,CAAC,IAAK;IACZ,MAAOA,CAAC;EACV,CAAC,CAAC;EACJ,OAAOJ,IAAI;AACb;AAEA,OAAO,eAAeK,oBAAoBA,CAACC,OAAO,EAAET,KAAK,EAAEU,WAAW,EAAE;EACtE,MAAMT,aAAa,GAAG;IACpBC,OAAO,EAAE;MAAE,cAAc,EAAE;IAAoC;EACjE,CAAC;EACD,MAAMS,GAAG,GAAG,IAAIC,GAAG,CAAE,GAAEhB,SAAS,CAAC,CAAC,CAACS,YAAa,mBAAkBL,KAAM,GAAE,CAAC;EAE3E,IAAIU,WAAW,CAACG,mBAAmB,EAAE;IACnCF,GAAG,CAACG,YAAY,CAACC,MAAM,CAAC,qBAAqB,EAAE,IAAI,CAAC;EACtD;EAEA,MAAM;IAAEZ;EAAK,CAAC,GAAG,MAAMN,aAAa,CAAC,CAAC,CACnCO,IAAI,CAACO,GAAG,CAACK,IAAI,EAAElB,cAAc,CAACW,OAAO,CAAC,EAAER,aAAa,CAAC,CACtDK,KAAK,CAAEC,CAAC,IAAK;IACZ,MAAOA,CAAC;EACV,CAAC,CAAC;EACJ,OAAOJ,IAAI;AACb;AAEA,OAAO,eAAec,uBAAuBA,CAACR,OAAO,EAAE;EACrD,MAAMR,aAAa,GAAG;IACpBC,OAAO,EAAE;MAAE,cAAc,EAAE;IAAoC;EACjE,CAAC;EACD,MAAM;IAAEC;EAAK,CAAC,GAAG,MAAMN,aAAa,CAAC,CAAC,CACnCO,IAAI,CACF,GAAER,SAAS,CAAC,CAAC,CAACS,YAAa,sCAAqC,EACjEP,cAAc,CAACW,OAAO,CAAC,EACvBR,aACF,CAAC,CACAK,KAAK,CAAEC,CAAC,IAAK;IACZ,MAAOA,CAAC;EACV,CAAC,CAAC;EAEJ,IAAIW,YAAY,GAAG,EAAE;EACrB;EACA;EACA,IAAIf,IAAI,CAACgB,oBAAoB,IAAIhB,IAAI,CAACgB,oBAAoB,CAACC,QAAQ,EAAE;IACnEF,YAAY,GAAGf,IAAI,CAACgB,oBAAoB,CAACC,QAAQ;EACnD;EAEA,OAAOF,YAAY;AACrB","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/reset-password-popup/reset-password/index.js b/dist/forms/reset-password-popup/reset-password/index.js new file mode 100644 index 00000000..50240ba9 --- /dev/null +++ b/dist/forms/reset-password-popup/reset-password/index.js @@ -0,0 +1,211 @@ +function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } +function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } +function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); } +function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Container, Form, Spinner, StatefulButton } from '@openedx/paragon'; +import ResetPasswordFailure from './components/ResetPasswordFailure'; +import { PASSWORD_RESET, PASSWORD_RESET_ERROR, PASSWORD_VALIDATION_ERROR, SUCCESS, TOKEN_STATE } from './data/constants'; +import { resetPassword, validatePassword, validateToken } from './data/reducers'; +import { setCurrentOpenedForm } from '../../../authn-component/data/reducers'; +import { COMPLETE_STATE, DEFAULT_STATE, FORGOT_PASSWORD_FORM, FORM_SUBMISSION_ERROR, LOGIN_FORM, PENDING_STATE } from '../../../data/constants'; +import { useDispatch, useSelector } from '../../../data/storeHooks'; +import getAllPossibleQueryParams from '../../../data/utils'; +import { trackPasswordResetSuccess, trackResetPasswordPageViewed } from '../../../tracking/trackers/reset-password'; +import { PasswordField } from '../../fields'; +import messages from '../messages'; +import ResetPasswordHeader from '../ResetPasswordHeader'; +export const LETTER_REGEX = /[a-zA-Z]/; +export const NUMBER_REGEX = /\d/; + +/** + * ResetPasswordForm component for completing user password reset. + * This component provides a form for users to reset their password. + * @returns {string} A message indicating the success or failure of the password reset process. + */ +const ResetPasswordPage = () => { + const dispatch = useDispatch(); + const queryParams = useMemo(() => getAllPossibleQueryParams(), []); + const passwordResetToken = queryParams?.password_reset_token; + + // const ResetPasswordPage = ({ errorMsg = null }) => { + const { + formatMessage + } = useIntl(); + const [newPassword, setNewPassword] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); + const [formErrors, setFormErrors] = useState({}); + const [errorCode, setErrorCode] = useState(null); + const newPasswordRef = useRef(null); + const status = useSelector(state => state.resetPassword.status); + const tokenValidationState = useSelector(state => state.resetPassword.status); + const errorMsg = useSelector(state => state.resetPassword?.errorMsg); + const backendValidationError = useSelector(state => state.resetPassword?.backendValidationError); + const validatePasswordFromBackend = password => { + const payload = { + reset_password_page: true, + password + }; + dispatch(validatePassword(payload)); + }; + useEffect(() => { + if (passwordResetToken) { + dispatch(validateToken(passwordResetToken)); + } + }, [dispatch, passwordResetToken]); + useEffect(() => { + setFormErrors(preState => _objectSpread(_objectSpread({}, preState), {}, { + newPassword: backendValidationError || '' + })); + }, [backendValidationError]); + useEffect(() => { + if (status === TOKEN_STATE.VALID && newPasswordRef.current) { + newPasswordRef.current.focus(); + } + }, [status]); + useEffect(() => { + if (tokenValidationState === COMPLETE_STATE && status === TOKEN_STATE.VALID) { + trackResetPasswordPageViewed(); + } + }, [status, tokenValidationState]); + const validateInput = function (name, value) { + let shouldValidateFromBackend = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; + switch (name) { + case 'newPassword': + if (!value) { + formErrors.newPassword = formatMessage(messages.passwordRequiredMessage); + } else if (!LETTER_REGEX.test(value) || !NUMBER_REGEX.test(value) || value.length < 8) { + formErrors.newPassword = formatMessage(messages.passwordValidationMessage); + } else if (shouldValidateFromBackend) { + validatePasswordFromBackend(value); + } + break; + case 'confirmPassword': + if (!value) { + formErrors.confirmPassword = formatMessage(messages.confirmYourPassword); + } else if (value !== newPassword) { + formErrors.confirmPassword = formatMessage(messages.passwordDoNotMatch); + } else { + formErrors.confirmPassword = ''; + } + break; + default: + break; + } + setFormErrors(_objectSpread({}, formErrors)); + return !Object.values(formErrors).some(x => x !== ''); + }; + const handleOnBlur = event => { + const { + name, + value + } = event.target; + validateInput(name, value); + }; + const handleOnFocus = e => { + setFormErrors(_objectSpread(_objectSpread({}, formErrors), {}, { + [e.target.name]: '' + })); + }; + useEffect(() => { + if (status !== TOKEN_STATE.PENDING && status !== PASSWORD_RESET_ERROR) { + setErrorCode(status); + } + if (status === PASSWORD_VALIDATION_ERROR) { + setFormErrors({ + newPassword: formatMessage(messages.passwordValidationMessage) + }); + } + }, [status, formatMessage]); + const handleSubmit = e => { + e.preventDefault(); + const isPasswordValid = validateInput('newPassword', newPassword, false); + const isPasswordConfirmed = validateInput('confirmPassword', confirmPassword); + if (isPasswordValid && isPasswordConfirmed) { + const formPayload = { + new_password1: newPassword, + new_password2: confirmPassword + }; + const params = queryParams; + dispatch(resetPassword({ + formPayload, + token: passwordResetToken, + params + })); + } else { + setErrorCode(FORM_SUBMISSION_ERROR); + } + }; + if (!passwordResetToken) { + dispatch(setCurrentOpenedForm(FORGOT_PASSWORD_FORM)); + } + if (status === TOKEN_STATE.PENDING || status === PENDING_STATE) { + return /*#__PURE__*/React.createElement(Container, { + size: "lg", + className: "loader-container d-flex flex-column justify-content-center align-items-center my-6 w-100 h-100 text-center" + }, /*#__PURE__*/React.createElement("h1", { + className: "loader-heading text-center mb-4" + }, formatMessage(messages.resetPasswordTokenValidatingHeadingText)), /*#__PURE__*/React.createElement(Spinner, { + animation: "border", + variant: "primary", + className: "spinner--position-centered" + }), ";"); + } + if (status === PASSWORD_RESET_ERROR || status === PASSWORD_RESET.INVALID_TOKEN) { + dispatch(setCurrentOpenedForm(FORGOT_PASSWORD_FORM)); + } else if (status === SUCCESS) { + trackPasswordResetSuccess(); + dispatch(setCurrentOpenedForm(LOGIN_FORM)); + } + return /*#__PURE__*/React.createElement(Container, { + size: "lg", + className: "authn__popup-container overflow-auto" + }, /*#__PURE__*/React.createElement(ResetPasswordHeader, null), /*#__PURE__*/React.createElement(ResetPasswordFailure, { + errorCode: errorCode, + errorMsg: errorMsg + }), /*#__PURE__*/React.createElement("div", { + className: "text-gray-800 mb-4" + }, formatMessage(messages.enterConfirmPasswordMessage)), /*#__PURE__*/React.createElement(Form, { + id: "set-reset-password-form", + name: "set-reset-password-form", + className: "d-flex flex-column" + }, /*#__PURE__*/React.createElement(PasswordField, { + id: "newPassword", + name: "newPassword", + dataTestId: "newPassword", + value: newPassword, + handleChange: e => setNewPassword(e.target.value), + handleFocus: handleOnFocus, + handleBlur: handleOnBlur, + errorMessage: formErrors.newPassword, + floatingLabel: formatMessage(messages.newPasswordLabel), + ref: newPasswordRef + }), /*#__PURE__*/React.createElement(PasswordField, { + id: "confirmPassword", + name: "confirmPassword", + dataTestId: "confirmPassword", + value: confirmPassword, + handleChange: e => setConfirmPassword(e.target.value), + handleFocus: handleOnFocus, + handleBlur: handleOnBlur, + errorMessage: formErrors.confirmPassword, + floatingLabel: formatMessage(messages.confirmPasswordLabel) + }), /*#__PURE__*/React.createElement(StatefulButton, { + id: "reset-password", + name: "reset-password", + type: "submit", + variant: "primary", + className: "align-self-end authn-btn__pill-shaped", + state: DEFAULT_STATE, + labels: { + default: formatMessage(messages.resetPasswordButton), + pending: '' + }, + onClick: e => handleSubmit(e), + onMouseDown: e => e.preventDefault() + }))); +}; +export default ResetPasswordPage; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/forms/reset-password-popup/reset-password/index.js.map b/dist/forms/reset-password-popup/reset-password/index.js.map new file mode 100644 index 00000000..6a1d3050 --- /dev/null +++ b/dist/forms/reset-password-popup/reset-password/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["React","useEffect","useMemo","useRef","useState","useIntl","Container","Form","Spinner","StatefulButton","ResetPasswordFailure","PASSWORD_RESET","PASSWORD_RESET_ERROR","PASSWORD_VALIDATION_ERROR","SUCCESS","TOKEN_STATE","resetPassword","validatePassword","validateToken","setCurrentOpenedForm","COMPLETE_STATE","DEFAULT_STATE","FORGOT_PASSWORD_FORM","FORM_SUBMISSION_ERROR","LOGIN_FORM","PENDING_STATE","useDispatch","useSelector","getAllPossibleQueryParams","trackPasswordResetSuccess","trackResetPasswordPageViewed","PasswordField","messages","ResetPasswordHeader","LETTER_REGEX","NUMBER_REGEX","ResetPasswordPage","dispatch","queryParams","passwordResetToken","password_reset_token","formatMessage","newPassword","setNewPassword","confirmPassword","setConfirmPassword","formErrors","setFormErrors","errorCode","setErrorCode","newPasswordRef","status","state","tokenValidationState","errorMsg","backendValidationError","validatePasswordFromBackend","password","payload","reset_password_page","preState","_objectSpread","VALID","current","focus","validateInput","name","value","shouldValidateFromBackend","arguments","length","undefined","passwordRequiredMessage","test","passwordValidationMessage","confirmYourPassword","passwordDoNotMatch","Object","values","some","x","handleOnBlur","event","target","handleOnFocus","e","PENDING","handleSubmit","preventDefault","isPasswordValid","isPasswordConfirmed","formPayload","new_password1","new_password2","params","token","createElement","size","className","resetPasswordTokenValidatingHeadingText","animation","variant","INVALID_TOKEN","enterConfirmPasswordMessage","id","dataTestId","handleChange","handleFocus","handleBlur","errorMessage","floatingLabel","newPasswordLabel","ref","confirmPasswordLabel","type","labels","default","resetPasswordButton","pending","onClick","onMouseDown"],"sources":["../../../../src/forms/reset-password-popup/reset-password/index.jsx"],"sourcesContent":["import React, {\n useEffect, useMemo, useRef, useState,\n} from 'react';\n\nimport { useIntl } from '@edx/frontend-platform/i18n';\nimport {\n Container, Form, Spinner, StatefulButton,\n} from '@openedx/paragon';\n\nimport ResetPasswordFailure from './components/ResetPasswordFailure';\nimport {\n PASSWORD_RESET, PASSWORD_RESET_ERROR,\n PASSWORD_VALIDATION_ERROR, SUCCESS, TOKEN_STATE,\n} from './data/constants';\nimport { resetPassword, validatePassword, validateToken } from './data/reducers';\nimport { setCurrentOpenedForm } from '../../../authn-component/data/reducers';\nimport {\n COMPLETE_STATE,\n DEFAULT_STATE, FORGOT_PASSWORD_FORM, FORM_SUBMISSION_ERROR, LOGIN_FORM, PENDING_STATE,\n} from '../../../data/constants';\nimport { useDispatch, useSelector } from '../../../data/storeHooks';\nimport getAllPossibleQueryParams from '../../../data/utils';\nimport { trackPasswordResetSuccess, trackResetPasswordPageViewed } from '../../../tracking/trackers/reset-password';\nimport { PasswordField } from '../../fields';\nimport messages from '../messages';\nimport ResetPasswordHeader from '../ResetPasswordHeader';\n\nexport const LETTER_REGEX = /[a-zA-Z]/;\nexport const NUMBER_REGEX = /\\d/;\n\n/**\n * ResetPasswordForm component for completing user password reset.\n * This component provides a form for users to reset their password.\n * @returns {string} A message indicating the success or failure of the password reset process.\n */\nconst ResetPasswordPage = () => {\n const dispatch = useDispatch();\n\n const queryParams = useMemo(() => getAllPossibleQueryParams(), []);\n const passwordResetToken = queryParams?.password_reset_token;\n\n // const ResetPasswordPage = ({ errorMsg = null }) => {\n const { formatMessage } = useIntl();\n const [newPassword, setNewPassword] = useState('');\n const [confirmPassword, setConfirmPassword] = useState('');\n const [formErrors, setFormErrors] = useState({});\n const [errorCode, setErrorCode] = useState(null);\n\n const newPasswordRef = useRef(null);\n\n const status = useSelector(state => state.resetPassword.status);\n const tokenValidationState = useSelector(state => state.resetPassword.status);\n const errorMsg = useSelector(state => state.resetPassword?.errorMsg);\n const backendValidationError = useSelector(state => state.resetPassword?.backendValidationError);\n\n const validatePasswordFromBackend = (password) => {\n const payload = {\n reset_password_page: true,\n password,\n };\n dispatch(validatePassword(payload));\n };\n\n useEffect(() => {\n if (passwordResetToken) {\n dispatch(validateToken(passwordResetToken));\n }\n }, [dispatch, passwordResetToken]);\n\n useEffect(() => {\n setFormErrors((preState) => ({\n ...preState,\n newPassword: backendValidationError || '',\n }));\n }, [backendValidationError]);\n\n useEffect(() => {\n if (status === TOKEN_STATE.VALID && newPasswordRef.current) {\n newPasswordRef.current.focus();\n }\n }, [status]);\n\n useEffect(() => {\n if (tokenValidationState === COMPLETE_STATE && status === TOKEN_STATE.VALID) {\n trackResetPasswordPageViewed();\n }\n }, [status, tokenValidationState]);\n\n const validateInput = (name, value, shouldValidateFromBackend = true) => {\n switch (name) {\n case 'newPassword':\n if (!value) {\n formErrors.newPassword = formatMessage(messages.passwordRequiredMessage);\n } else if (!LETTER_REGEX.test(value) || !NUMBER_REGEX.test(value) || value.length < 8) {\n formErrors.newPassword = formatMessage(messages.passwordValidationMessage);\n } else if (shouldValidateFromBackend) {\n validatePasswordFromBackend(value);\n }\n break;\n case 'confirmPassword':\n if (!value) {\n formErrors.confirmPassword = formatMessage(messages.confirmYourPassword);\n } else if (value !== newPassword) {\n formErrors.confirmPassword = formatMessage(messages.passwordDoNotMatch);\n } else {\n formErrors.confirmPassword = '';\n }\n break;\n default:\n break;\n }\n setFormErrors({ ...formErrors });\n return !Object.values(formErrors).some(x => (x !== ''));\n };\n\n const handleOnBlur = (event) => {\n const { name, value } = event.target;\n validateInput(name, value);\n };\n\n const handleOnFocus = (e) => {\n setFormErrors({ ...formErrors, [e.target.name]: '' });\n };\n\n useEffect(() => {\n if (status !== TOKEN_STATE.PENDING && status !== PASSWORD_RESET_ERROR) {\n setErrorCode(status);\n }\n if (status === PASSWORD_VALIDATION_ERROR) {\n setFormErrors({ newPassword: formatMessage(messages.passwordValidationMessage) });\n }\n }, [status, formatMessage]);\n\n const handleSubmit = (e) => {\n e.preventDefault();\n\n const isPasswordValid = validateInput('newPassword', newPassword, false);\n const isPasswordConfirmed = validateInput('confirmPassword', confirmPassword);\n if (isPasswordValid && isPasswordConfirmed) {\n const formPayload = {\n new_password1: newPassword,\n new_password2: confirmPassword,\n };\n const params = queryParams;\n dispatch(resetPassword({ formPayload, token: passwordResetToken, params }));\n } else {\n setErrorCode(FORM_SUBMISSION_ERROR);\n }\n };\n\n if (!passwordResetToken) {\n dispatch(setCurrentOpenedForm(FORGOT_PASSWORD_FORM));\n }\n\n if (status === TOKEN_STATE.PENDING || status === PENDING_STATE) {\n return (\n \n

{formatMessage(messages.resetPasswordTokenValidatingHeadingText)}

\n ;\n \n );\n } if (status === PASSWORD_RESET_ERROR || status === PASSWORD_RESET.INVALID_TOKEN) {\n dispatch(setCurrentOpenedForm(FORGOT_PASSWORD_FORM));\n } else if (status === SUCCESS) {\n trackPasswordResetSuccess();\n dispatch(setCurrentOpenedForm(LOGIN_FORM));\n }\n\n return (\n \n \n \n
{formatMessage(messages.enterConfirmPasswordMessage)}
\n
\n setNewPassword(e.target.value)}\n handleFocus={handleOnFocus}\n handleBlur={handleOnBlur}\n errorMessage={formErrors.newPassword}\n floatingLabel={formatMessage(messages.newPasswordLabel)}\n ref={newPasswordRef}\n />\n setConfirmPassword(e.target.value)}\n handleFocus={handleOnFocus}\n handleBlur={handleOnBlur}\n errorMessage={formErrors.confirmPassword}\n floatingLabel={formatMessage(messages.confirmPasswordLabel)}\n />\n handleSubmit(e)}\n onMouseDown={(e) => e.preventDefault()}\n />\n \n
\n );\n};\n\nexport default ResetPasswordPage;\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/forms/reset-password-popup/reset-password/messages.js b/dist/forms/reset-password-popup/reset-password/messages.js new file mode 100644 index 00000000..6ef9e01d --- /dev/null +++ b/dist/forms/reset-password-popup/reset-password/messages.js @@ -0,0 +1,26 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; +const messages = defineMessages({ + // alert banner strings + resetPasswordFormSubmissionError: { + id: 'reset.password.form.submission.error', + defaultMessage: 'Please check your responses and try again.', + description: 'Error message for reset password page' + }, + resetPassowrdSuccess: { + id: 'reset.password.success', + defaultMessage: 'Your password has been reset. Sign in to your account.', + description: 'Reset password success message' + }, + internalServerError: { + id: 'internal.server.error', + defaultMessage: 'An error has occurred. Try refreshing the page, or check your internet connection.', + description: 'Error message that appears when server responds with 500 error code' + }, + rateLimitError: { + id: 'rate.limit.error', + defaultMessage: 'An error has occurred because of too many requests. Please try again after some time.', + description: 'Error message that appears when server responds with 429 error code' + } +}); +export default messages; +//# sourceMappingURL=messages.js.map \ No newline at end of file diff --git a/dist/forms/reset-password-popup/reset-password/messages.js.map b/dist/forms/reset-password-popup/reset-password/messages.js.map new file mode 100644 index 00000000..2ea80bdb --- /dev/null +++ b/dist/forms/reset-password-popup/reset-password/messages.js.map @@ -0,0 +1 @@ +{"version":3,"file":"messages.js","names":["defineMessages","messages","resetPasswordFormSubmissionError","id","defaultMessage","description","resetPassowrdSuccess","internalServerError","rateLimitError"],"sources":["../../../../src/forms/reset-password-popup/reset-password/messages.js"],"sourcesContent":["import { defineMessages } from '@edx/frontend-platform/i18n';\n\nconst messages = defineMessages({\n // alert banner strings\n resetPasswordFormSubmissionError: {\n id: 'reset.password.form.submission.error',\n defaultMessage: 'Please check your responses and try again.',\n description: 'Error message for reset password page',\n },\n resetPassowrdSuccess: {\n id: 'reset.password.success',\n defaultMessage: 'Your password has been reset. Sign in to your account.',\n description: 'Reset password success message',\n },\n internalServerError: {\n id: 'internal.server.error',\n defaultMessage: 'An error has occurred. Try refreshing the page, or check your internet connection.',\n description: 'Error message that appears when server responds with 500 error code',\n },\n rateLimitError: {\n id: 'rate.limit.error',\n defaultMessage: 'An error has occurred because of too many requests. Please try again after some time.',\n description: 'Error message that appears when server responds with 429 error code',\n },\n});\n\nexport default messages;\n"],"mappings":"AAAA,SAASA,cAAc,QAAQ,6BAA6B;AAE5D,MAAMC,QAAQ,GAAGD,cAAc,CAAC;EAC9B;EACAE,gCAAgC,EAAE;IAChCC,EAAE,EAAE,sCAAsC;IAC1CC,cAAc,EAAE,4CAA4C;IAC5DC,WAAW,EAAE;EACf,CAAC;EACDC,oBAAoB,EAAE;IACpBH,EAAE,EAAE,wBAAwB;IAC5BC,cAAc,EAAE,wDAAwD;IACxEC,WAAW,EAAE;EACf,CAAC;EACDE,mBAAmB,EAAE;IACnBJ,EAAE,EAAE,uBAAuB;IAC3BC,cAAc,EAAE,oFAAoF;IACpGC,WAAW,EAAE;EACf,CAAC;EACDG,cAAc,EAAE;IACdL,EAAE,EAAE,kBAAkB;IACtBC,cAAc,EAAE,uFAAuF;IACvGC,WAAW,EAAE;EACf;AACF,CAAC,CAAC;AAEF,eAAeJ,QAAQ","ignoreList":[]} \ No newline at end of file diff --git a/dist/i18n/index.js b/dist/i18n/index.js new file mode 100644 index 00000000..f9d24dcc --- /dev/null +++ b/dist/i18n/index.js @@ -0,0 +1,9 @@ +import esMessages from './messages/es_419.json'; + +// Placeholder be overridden by `make pull_translations` +const messages = { + 'es-419': esMessages, + es: esMessages +}; +export default messages; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/i18n/index.js.map b/dist/i18n/index.js.map new file mode 100644 index 00000000..f1e2165d --- /dev/null +++ b/dist/i18n/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["esMessages","messages","es"],"sources":["../../src/i18n/index.js"],"sourcesContent":["import esMessages from './messages/es_419.json';\n\n// Placeholder be overridden by `make pull_translations`\nconst messages = {\n 'es-419': esMessages,\n es: esMessages,\n}\n\nexport default messages;\n"],"mappings":"AAAA,OAAOA,UAAU,MAAM,wBAAwB;;AAE/C;AACA,MAAMC,QAAQ,GAAG;EACf,QAAQ,EAAED,UAAU;EACpBE,EAAE,EAAEF;AACN,CAAC;AAED,eAAeC,QAAQ","ignoreList":[]} \ No newline at end of file diff --git a/dist/i18n/messages/es_419.json b/dist/i18n/messages/es_419.json new file mode 100644 index 00000000..fa173649 --- /dev/null +++ b/dist/i18n/messages/es_419.json @@ -0,0 +1,3 @@ +{ + "login.form.heading.1": "Iniciar sesión" +} diff --git a/dist/i18n/module.config.js.map b/dist/i18n/module.config.js.map new file mode 100644 index 00000000..8feb4c6a --- /dev/null +++ b/dist/i18n/module.config.js.map @@ -0,0 +1 @@ +{"version":3,"file":"module.config.js","names":[],"sources":["../../src/i18n/module.config.js"],"sourcesContent":["// module.exports = {\n// /*\n// Modules you want to use from local source code. Adding a module here means that when this app\n// runs its build, it'll resolve the source from peer directories of this app.\n \n// moduleName: the name you use to import code from the module.\n// dir: The relative path to the module's source code.\n// dist: The sub-directory of the source code where it puts its build artifact. Often \"dist\".\n// */\n// localModules: [\n// { moduleName: '@openedx/paragon/scss/core', dir: '../paragon', dist: 'scss/core' },\n// { moduleName: '@openedx/paragon/icons', dir: '../paragon', dist: 'icons' },\n// { moduleName: '@openedx/paragon', dir: '../paragon', dist: 'dist' },\n// ],\n \n// };"],"mappings":"AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA","ignoreList":[]} \ No newline at end of file diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 00000000..b9ce0144 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,3 @@ +import { ResetPasswordComponent, SignInComponent, SignUpComponent } from './authn-component'; +export { SignUpComponent, SignInComponent, ResetPasswordComponent }; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/index.js.map b/dist/index.js.map new file mode 100644 index 00000000..360a3787 --- /dev/null +++ b/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","names":["ResetPasswordComponent","SignInComponent","SignUpComponent"],"sources":["../src/index.jsx"],"sourcesContent":["import {\n ResetPasswordComponent, SignInComponent, SignUpComponent,\n} from './authn-component';\n\nexport {\n SignUpComponent,\n SignInComponent,\n ResetPasswordComponent,\n};\n"],"mappings":"AAAA,SACEA,sBAAsB,EAAEC,eAAe,EAAEC,eAAe,QACnD,mBAAmB;AAE1B,SACEA,eAAe,EACfD,eAAe,EACfD,sBAAsB","ignoreList":[]} \ No newline at end of file diff --git a/dist/index.scss b/dist/index.scss new file mode 100644 index 00000000..d519bf5b --- /dev/null +++ b/dist/index.scss @@ -0,0 +1,54 @@ +@import "~@edx/brand-edx.org/paragon/variables"; +@import "common-ui"; +@import "base-container"; +@import "forms"; + +.authn-component__modal .authn-btn__pill-shaped { + border-radius: 100px !important; + padding: 10px 24px !important; + justify-content: center !important; + align-items: center !important; +} + +.authn-component__modal .authn-sso-btn__pill-shaped { + border-radius: 6px !important; + box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.17), 0 0 3px 0 rgba(0, 0, 0, 0.08); +} + +.authn-component__modal .pgn__form-group .pgn__form-control-decorator-group input { + border-radius: 5px !important; +} + +.authn__popup-container { + padding: 2.5rem !important; +} + +.authn-popup__registration-footer { + padding: 2.5rem !important; +} + +@media (max-width: 576px) { + .authn__popup-container { + padding: 1rem !important; + } + + .authn-popup__registration-footer { + padding: 1rem 1.5rem !important; + } +} + +@media (max-width: 350px) { + .authn-popup__registration-footer { + padding: 1rem !important; + } +} + +.authn__popup-container .pgn__form-control-floating-label-text:after { + content: "*" !important; + color: $danger-500 !important; +} + +.heading-separator { + border: 0 !important; + border-top: 0.075rem solid $light-500 !important; +} diff --git a/dist/package.json b/dist/package.json new file mode 100644 index 00000000..fd8eb0f3 --- /dev/null +++ b/dist/package.json @@ -0,0 +1,86 @@ +{ + "name": "@edx/frontend-component-authn-edx", + "version": "1.0.0-semantically-released", + "description": "Authentication related forms for edX", + "main": "index.js", + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "make build", + "i18n_extract": "fedx-scripts formatjs extract", + "lint": "fedx-scripts eslint --ext .js --ext .jsx .", + "lint:fix": "fedx-scripts eslint --fix --ext .js --ext .jsx .", + "snapshot": "fedx-scripts jest --updateSnapshot", + "start": "fedx-scripts webpack-dev-server --progress", + "test": "fedx-scripts jest --coverage --passWithNoTests" + }, + "browserslist": [ + "extends @edx/browserslist-config" + ], + "husky": { + "hooks": { + "pre-commit": "npm run lint" + } + }, + "author": "edX", + "license": "AGPL-3.0", + "homepage": "https://github.com/edx/frontend-component-authn-edx#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/edx/frontend-component-authn-edx.git" + }, + "bugs": { + "url": "https://github.com/edx/frontend-component-authn-edx/issues" + }, + "dependencies": { + "@edx/brand-edx.org": "^2.0.4", + "@fortawesome/fontawesome-svg-core": "1.2.36", + "@fortawesome/free-brands-svg-icons": "5.15.4", + "@fortawesome/free-regular-svg-icons": "5.15.4", + "@fortawesome/free-solid-svg-icons": "5.15.4", + "@fortawesome/react-fontawesome": "0.2.0", + "@openedx/paragon": "^22.0.0", + "@redux-devtools/extension": "3.3.0", + "@reduxjs/toolkit": "^2.2.3", + "@testing-library/react": "^12.1.5", + "@testing-library/react-hooks": "^8.0.1", + "algoliasearch": "^4.23.3", + "algoliasearch-helper": "^3.18.0", + "classnames": "^2.5.1", + "core-js": "3.36.0", + "fastest-levenshtein": "^1.0.16", + "form-urlencoded": "^6.1.5", + "query-string": "^7.1.3", + "react-redux": "7.2.9", + "react-router": "6.22.3", + "react-router-dom": "6.22.3", + "redux": "4.2.0", + "redux-logger": "3.0.6", + "redux-mock-store": "1.5.4", + "redux-saga": "1.3.0", + "redux-thunk": "2.4.2", + "regenerator-runtime": "0.14.1", + "reselect": "^5.1.0", + "universal-cookie": "^6.0.1" + }, + "devDependencies": { + "@edx/browserslist-config": "^1.1.1", + "@edx/frontend-build": "13.0.0", + "@edx/reactifex": "^2.1.1", + "glob": "7.2.3", + "husky": "7.0.4", + "jest": "29.7.0", + "prop-types": "15.8.1", + "react": "17.0.2", + "react-dom": "17.0.2", + "redux": "4.2.0" + }, + "peerDependencies": { + "@edx/frontend-platform": "^7.1.0", + "@openedx/paragon": "^22.0.0", + "prop-types": "^15.8.0", + "react": "^17.0.0", + "react-dom": "^17.0.0" + } +} diff --git a/dist/tracking/trackers/forgotpassword.js b/dist/tracking/trackers/forgotpassword.js new file mode 100644 index 00000000..6597b3f9 --- /dev/null +++ b/dist/tracking/trackers/forgotpassword.js @@ -0,0 +1,17 @@ +import { createEventTracker, createPageEventTracker } from '../../data/segment/utils'; +export const eventNames = { + loginAndRegistration: 'login_and_registration', + forgotPasswordPageViewed: 'edx.bi.password_reset_form.viewed' +}; +export const categories = { + userEngagement: 'user-engagement' +}; + +// Event tracker for forgot password page viewed +export const trackForgotPasswordPageViewed = () => createEventTracker(eventNames.forgotPasswordPageViewed, { + category: categories.userEngagement +})(); +export const trackForgotPasswordPageEvent = () => { + createPageEventTracker(eventNames.loginAndRegistration, 'forgot-password')(); +}; +//# sourceMappingURL=forgotpassword.js.map \ No newline at end of file diff --git a/dist/tracking/trackers/forgotpassword.js.map b/dist/tracking/trackers/forgotpassword.js.map new file mode 100644 index 00000000..bae2b61d --- /dev/null +++ b/dist/tracking/trackers/forgotpassword.js.map @@ -0,0 +1 @@ +{"version":3,"file":"forgotpassword.js","names":["createEventTracker","createPageEventTracker","eventNames","loginAndRegistration","forgotPasswordPageViewed","categories","userEngagement","trackForgotPasswordPageViewed","category","trackForgotPasswordPageEvent"],"sources":["../../../src/tracking/trackers/forgotpassword.js"],"sourcesContent":["import { createEventTracker, createPageEventTracker } from '../../data/segment/utils';\n\nexport const eventNames = {\n loginAndRegistration: 'login_and_registration',\n forgotPasswordPageViewed: 'edx.bi.password_reset_form.viewed',\n};\n\nexport const categories = {\n userEngagement: 'user-engagement',\n};\n\n// Event tracker for forgot password page viewed\nexport const trackForgotPasswordPageViewed = () => createEventTracker(\n eventNames.forgotPasswordPageViewed,\n {\n category: categories.userEngagement,\n },\n)();\n\nexport const trackForgotPasswordPageEvent = () => {\n createPageEventTracker(eventNames.loginAndRegistration, 'forgot-password')();\n};\n"],"mappings":"AAAA,SAASA,kBAAkB,EAAEC,sBAAsB,QAAQ,0BAA0B;AAErF,OAAO,MAAMC,UAAU,GAAG;EACxBC,oBAAoB,EAAE,wBAAwB;EAC9CC,wBAAwB,EAAE;AAC5B,CAAC;AAED,OAAO,MAAMC,UAAU,GAAG;EACxBC,cAAc,EAAE;AAClB,CAAC;;AAED;AACA,OAAO,MAAMC,6BAA6B,GAAGA,CAAA,KAAMP,kBAAkB,CACnEE,UAAU,CAACE,wBAAwB,EACnC;EACEI,QAAQ,EAAEH,UAAU,CAACC;AACvB,CACF,CAAC,CAAC,CAAC;AAEH,OAAO,MAAMG,4BAA4B,GAAGA,CAAA,KAAM;EAChDR,sBAAsB,CAACC,UAAU,CAACC,oBAAoB,EAAE,iBAAiB,CAAC,CAAC,CAAC;AAC9E,CAAC","ignoreList":[]} \ No newline at end of file diff --git a/dist/tracking/trackers/login.js b/dist/tracking/trackers/login.js new file mode 100644 index 00000000..872f4e6f --- /dev/null +++ b/dist/tracking/trackers/login.js @@ -0,0 +1,31 @@ +import { createEventTracker, createPageEventTracker } from '../../data/segment/utils'; +export const eventNames = { + forgotPasswordLinkClicked: 'edx.bi.password-reset_form.toggled', + loginAndRegistration: 'login_and_registration', + registerFormToggled: 'edx.bi.register_form.toggled', + loginSuccess: 'edx.bi.user.account.authenticated.client' +}; +export const categories = { + userEngagement: 'user-engagement' +}; + +// Event tracker for Forgot Password link click +export const trackForgotPasswordLinkClick = () => createEventTracker(eventNames.forgotPasswordLinkClicked, { + category: categories.userEngagement +})(); + +// Tracks the login page event. +export const trackLoginPageViewed = () => { + createPageEventTracker(eventNames.loginAndRegistration, 'login')(); +}; + +// Tracks the progressive profiling page event. +export const trackRegisterFormToggled = () => { + createEventTracker(eventNames.registerFormToggled, { + category: categories.userEngagement + })(); +}; + +// Tracks the login sucess event. +export const trackLoginSuccess = () => createEventTracker(eventNames.loginSuccess, {})(); +//# sourceMappingURL=login.js.map \ No newline at end of file diff --git a/dist/tracking/trackers/login.js.map b/dist/tracking/trackers/login.js.map new file mode 100644 index 00000000..2a21db86 --- /dev/null +++ b/dist/tracking/trackers/login.js.map @@ -0,0 +1 @@ +{"version":3,"file":"login.js","names":["createEventTracker","createPageEventTracker","eventNames","forgotPasswordLinkClicked","loginAndRegistration","registerFormToggled","loginSuccess","categories","userEngagement","trackForgotPasswordLinkClick","category","trackLoginPageViewed","trackRegisterFormToggled","trackLoginSuccess"],"sources":["../../../src/tracking/trackers/login.js"],"sourcesContent":["import { createEventTracker, createPageEventTracker } from '../../data/segment/utils';\n\nexport const eventNames = {\n forgotPasswordLinkClicked: 'edx.bi.password-reset_form.toggled',\n loginAndRegistration: 'login_and_registration',\n registerFormToggled: 'edx.bi.register_form.toggled',\n loginSuccess: 'edx.bi.user.account.authenticated.client',\n};\n\nexport const categories = {\n userEngagement: 'user-engagement',\n};\n\n// Event tracker for Forgot Password link click\nexport const trackForgotPasswordLinkClick = () => createEventTracker(\n eventNames.forgotPasswordLinkClicked,\n { category: categories.userEngagement },\n)();\n\n// Tracks the login page event.\nexport const trackLoginPageViewed = () => {\n createPageEventTracker(eventNames.loginAndRegistration, 'login')();\n};\n\n// Tracks the progressive profiling page event.\nexport const trackRegisterFormToggled = () => {\n createEventTracker(\n eventNames.registerFormToggled,\n { category: categories.userEngagement },\n )();\n};\n\n// Tracks the login sucess event.\nexport const trackLoginSuccess = () => createEventTracker(\n eventNames.loginSuccess,\n {},\n)();\n"],"mappings":"AAAA,SAASA,kBAAkB,EAAEC,sBAAsB,QAAQ,0BAA0B;AAErF,OAAO,MAAMC,UAAU,GAAG;EACxBC,yBAAyB,EAAE,oCAAoC;EAC/DC,oBAAoB,EAAE,wBAAwB;EAC9CC,mBAAmB,EAAE,8BAA8B;EACnDC,YAAY,EAAE;AAChB,CAAC;AAED,OAAO,MAAMC,UAAU,GAAG;EACxBC,cAAc,EAAE;AAClB,CAAC;;AAED;AACA,OAAO,MAAMC,4BAA4B,GAAGA,CAAA,KAAMT,kBAAkB,CAClEE,UAAU,CAACC,yBAAyB,EACpC;EAAEO,QAAQ,EAAEH,UAAU,CAACC;AAAe,CACxC,CAAC,CAAC,CAAC;;AAEH;AACA,OAAO,MAAMG,oBAAoB,GAAGA,CAAA,KAAM;EACxCV,sBAAsB,CAACC,UAAU,CAACE,oBAAoB,EAAE,OAAO,CAAC,CAAC,CAAC;AACpE,CAAC;;AAED;AACA,OAAO,MAAMQ,wBAAwB,GAAGA,CAAA,KAAM;EAC5CZ,kBAAkB,CAChBE,UAAU,CAACG,mBAAmB,EAC9B;IAAEK,QAAQ,EAAEH,UAAU,CAACC;EAAe,CACxC,CAAC,CAAC,CAAC;AACL,CAAC;;AAED;AACA,OAAO,MAAMK,iBAAiB,GAAGA,CAAA,KAAMb,kBAAkB,CACvDE,UAAU,CAACI,YAAY,EACvB,CAAC,CACH,CAAC,CAAC,CAAC","ignoreList":[]} \ No newline at end of file diff --git a/dist/tracking/trackers/progressive-profiling.js b/dist/tracking/trackers/progressive-profiling.js new file mode 100644 index 00000000..34db3a53 --- /dev/null +++ b/dist/tracking/trackers/progressive-profiling.js @@ -0,0 +1,23 @@ +function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } +function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } +function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); } +function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } +import { createEventTracker, createLinkTracker, createPageEventTracker } from '../../data/segment/utils'; +export const eventNames = { + progressiveProfilingSubmitClick: 'edx.bi.welcome.page.submit.clicked', + progressiveProfilingSkipLinkClick: 'edx.bi.welcome.page.skip.link.clicked', + loginAndRegistration: 'login_and_registration' +}; + +// Event link tracker for Progressive profiling skip button click +export const trackProgressiveProfilingSkipLinkClick = redirectUrl => createLinkTracker(createEventTracker(eventNames.progressiveProfilingSkipLinkClick, {}), redirectUrl); + +// Event tracker for progressive profiling submit button click +export const trackProgressiveProfilingSubmitClick = evenProperties => createEventTracker(eventNames.progressiveProfilingSubmitClick, _objectSpread({}, evenProperties))(); + +// Tracks the progressive profiling page event. +export const trackProgressiveProfilingPageViewed = () => { + createPageEventTracker(eventNames.loginAndRegistration, 'welcome')(); +}; +//# sourceMappingURL=progressive-profiling.js.map \ No newline at end of file diff --git a/dist/tracking/trackers/progressive-profiling.js.map b/dist/tracking/trackers/progressive-profiling.js.map new file mode 100644 index 00000000..5fe87554 --- /dev/null +++ b/dist/tracking/trackers/progressive-profiling.js.map @@ -0,0 +1 @@ +{"version":3,"file":"progressive-profiling.js","names":["createEventTracker","createLinkTracker","createPageEventTracker","eventNames","progressiveProfilingSubmitClick","progressiveProfilingSkipLinkClick","loginAndRegistration","trackProgressiveProfilingSkipLinkClick","redirectUrl","trackProgressiveProfilingSubmitClick","evenProperties","_objectSpread","trackProgressiveProfilingPageViewed"],"sources":["../../../src/tracking/trackers/progressive-profiling.js"],"sourcesContent":["import { createEventTracker, createLinkTracker, createPageEventTracker } from '../../data/segment/utils';\n\nexport const eventNames = {\n progressiveProfilingSubmitClick: 'edx.bi.welcome.page.submit.clicked',\n progressiveProfilingSkipLinkClick: 'edx.bi.welcome.page.skip.link.clicked',\n loginAndRegistration: 'login_and_registration',\n};\n\n// Event link tracker for Progressive profiling skip button click\nexport const trackProgressiveProfilingSkipLinkClick = (redirectUrl) => createLinkTracker(\n createEventTracker(eventNames.progressiveProfilingSkipLinkClick, {}),\n redirectUrl,\n);\n\n// Event tracker for progressive profiling submit button click\nexport const trackProgressiveProfilingSubmitClick = (evenProperties) => createEventTracker(\n eventNames.progressiveProfilingSubmitClick,\n { ...evenProperties },\n)();\n\n// Tracks the progressive profiling page event.\nexport const trackProgressiveProfilingPageViewed = () => {\n createPageEventTracker(eventNames.loginAndRegistration, 'welcome')();\n};\n"],"mappings":";;;;;AAAA,SAASA,kBAAkB,EAAEC,iBAAiB,EAAEC,sBAAsB,QAAQ,0BAA0B;AAExG,OAAO,MAAMC,UAAU,GAAG;EACxBC,+BAA+B,EAAE,oCAAoC;EACrEC,iCAAiC,EAAE,uCAAuC;EAC1EC,oBAAoB,EAAE;AACxB,CAAC;;AAED;AACA,OAAO,MAAMC,sCAAsC,GAAIC,WAAW,IAAKP,iBAAiB,CACtFD,kBAAkB,CAACG,UAAU,CAACE,iCAAiC,EAAE,CAAC,CAAC,CAAC,EACpEG,WACF,CAAC;;AAED;AACA,OAAO,MAAMC,oCAAoC,GAAIC,cAAc,IAAKV,kBAAkB,CACxFG,UAAU,CAACC,+BAA+B,EAAAO,aAAA,KACrCD,cAAc,CACrB,CAAC,CAAC,CAAC;;AAEH;AACA,OAAO,MAAME,mCAAmC,GAAGA,CAAA,KAAM;EACvDV,sBAAsB,CAACC,UAAU,CAACG,oBAAoB,EAAE,SAAS,CAAC,CAAC,CAAC;AACtE,CAAC","ignoreList":[]} \ No newline at end of file diff --git a/dist/tracking/trackers/register.js b/dist/tracking/trackers/register.js new file mode 100644 index 00000000..de251e21 --- /dev/null +++ b/dist/tracking/trackers/register.js @@ -0,0 +1,25 @@ +import { createEventTracker, createPageEventTracker } from '../../data/segment/utils'; +export const eventNames = { + loginAndRegistration: 'login_and_registration', + registrationSuccess: 'edx.bi.user.account.registered.client', + loginFormToggled: 'edx.bi.login_form.toggled' +}; +export const categories = { + userEngagement: 'user-engagement' +}; + +// Event tracker for successful registration +export const trackRegistrationSuccess = () => createEventTracker(eventNames.registrationSuccess, {})(); + +// Tracks the progressive profiling page event. +export const trackRegistrationPageViewed = () => { + createPageEventTracker(eventNames.loginAndRegistration, 'register')(); +}; + +// Tracks the progressive profiling page event. +export const trackLoginFormToggled = () => { + createEventTracker(eventNames.loginFormToggled, { + category: categories.userEngagement + })(); +}; +//# sourceMappingURL=register.js.map \ No newline at end of file diff --git a/dist/tracking/trackers/register.js.map b/dist/tracking/trackers/register.js.map new file mode 100644 index 00000000..1c3a9e2c --- /dev/null +++ b/dist/tracking/trackers/register.js.map @@ -0,0 +1 @@ +{"version":3,"file":"register.js","names":["createEventTracker","createPageEventTracker","eventNames","loginAndRegistration","registrationSuccess","loginFormToggled","categories","userEngagement","trackRegistrationSuccess","trackRegistrationPageViewed","trackLoginFormToggled","category"],"sources":["../../../src/tracking/trackers/register.js"],"sourcesContent":["import { createEventTracker, createPageEventTracker } from '../../data/segment/utils';\n\nexport const eventNames = {\n loginAndRegistration: 'login_and_registration',\n registrationSuccess: 'edx.bi.user.account.registered.client',\n loginFormToggled: 'edx.bi.login_form.toggled',\n};\n\nexport const categories = {\n userEngagement: 'user-engagement',\n};\n\n// Event tracker for successful registration\nexport const trackRegistrationSuccess = () => createEventTracker(\n eventNames.registrationSuccess,\n {},\n)();\n\n// Tracks the progressive profiling page event.\nexport const trackRegistrationPageViewed = () => {\n createPageEventTracker(eventNames.loginAndRegistration, 'register')();\n};\n\n// Tracks the progressive profiling page event.\nexport const trackLoginFormToggled = () => {\n createEventTracker(\n eventNames.loginFormToggled,\n { category: categories.userEngagement },\n )();\n};\n"],"mappings":"AAAA,SAASA,kBAAkB,EAAEC,sBAAsB,QAAQ,0BAA0B;AAErF,OAAO,MAAMC,UAAU,GAAG;EACxBC,oBAAoB,EAAE,wBAAwB;EAC9CC,mBAAmB,EAAE,uCAAuC;EAC5DC,gBAAgB,EAAE;AACpB,CAAC;AAED,OAAO,MAAMC,UAAU,GAAG;EACxBC,cAAc,EAAE;AAClB,CAAC;;AAED;AACA,OAAO,MAAMC,wBAAwB,GAAGA,CAAA,KAAMR,kBAAkB,CAC9DE,UAAU,CAACE,mBAAmB,EAC9B,CAAC,CACH,CAAC,CAAC,CAAC;;AAEH;AACA,OAAO,MAAMK,2BAA2B,GAAGA,CAAA,KAAM;EAC/CR,sBAAsB,CAACC,UAAU,CAACC,oBAAoB,EAAE,UAAU,CAAC,CAAC,CAAC;AACvE,CAAC;;AAED;AACA,OAAO,MAAMO,qBAAqB,GAAGA,CAAA,KAAM;EACzCV,kBAAkB,CAChBE,UAAU,CAACG,gBAAgB,EAC3B;IAAEM,QAAQ,EAAEL,UAAU,CAACC;EAAe,CACxC,CAAC,CAAC,CAAC;AACL,CAAC","ignoreList":[]} \ No newline at end of file diff --git a/dist/tracking/trackers/reset-password.js b/dist/tracking/trackers/reset-password.js new file mode 100644 index 00000000..a7ce9ede --- /dev/null +++ b/dist/tracking/trackers/reset-password.js @@ -0,0 +1,12 @@ +import { createEventTracker, createPageEventTracker } from '../../data/segment/utils'; +export const eventNames = { + loginAndRegistration: 'login_and_registration', + resetPasswordSuccess: 'edx.bi.user.password.reset.success' +}; +export const trackResetPasswordPageViewed = () => { + createPageEventTracker(eventNames.loginAndRegistration, 'reset-password')(); +}; +export const trackPasswordResetSuccess = () => { + createEventTracker(eventNames.resetPasswordSuccess, {})(); +}; +//# sourceMappingURL=reset-password.js.map \ No newline at end of file diff --git a/dist/tracking/trackers/reset-password.js.map b/dist/tracking/trackers/reset-password.js.map new file mode 100644 index 00000000..bd201e86 --- /dev/null +++ b/dist/tracking/trackers/reset-password.js.map @@ -0,0 +1 @@ +{"version":3,"file":"reset-password.js","names":["createEventTracker","createPageEventTracker","eventNames","loginAndRegistration","resetPasswordSuccess","trackResetPasswordPageViewed","trackPasswordResetSuccess"],"sources":["../../../src/tracking/trackers/reset-password.js"],"sourcesContent":["import { createEventTracker, createPageEventTracker } from '../../data/segment/utils';\n\nexport const eventNames = {\n loginAndRegistration: 'login_and_registration',\n resetPasswordSuccess: 'edx.bi.user.password.reset.success',\n};\n\nexport const trackResetPasswordPageViewed = () => {\n createPageEventTracker(eventNames.loginAndRegistration, 'reset-password')();\n};\n\nexport const trackPasswordResetSuccess = () => {\n createEventTracker(eventNames.resetPasswordSuccess, {})();\n};\n"],"mappings":"AAAA,SAASA,kBAAkB,EAAEC,sBAAsB,QAAQ,0BAA0B;AAErF,OAAO,MAAMC,UAAU,GAAG;EACxBC,oBAAoB,EAAE,wBAAwB;EAC9CC,oBAAoB,EAAE;AACxB,CAAC;AAED,OAAO,MAAMC,4BAA4B,GAAGA,CAAA,KAAM;EAChDJ,sBAAsB,CAACC,UAAU,CAACC,oBAAoB,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED,OAAO,MAAMG,yBAAyB,GAAGA,CAAA,KAAM;EAC7CN,kBAAkB,CAACE,UAAU,CAACE,oBAAoB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3D,CAAC","ignoreList":[]} \ No newline at end of file diff --git a/example/index.jsx b/example/index.jsx index 5c3b8134..02e1b268 100644 --- a/example/index.jsx +++ b/example/index.jsx @@ -10,6 +10,7 @@ import { import './index.scss'; import AuthnExampleContainer from './authn-example'; +import messages from '../src/i18n/index' subscribe(APP_READY, () => { ReactDOM.render( @@ -19,7 +20,7 @@ subscribe(APP_READY, () => { }); initialize({ - messages: [], + messages: messages, handlers: { config: () => { mergeConfig({ diff --git a/src/i18n/index.js b/src/i18n/index.js index a47eb5b0..6b19689c 100644 --- a/src/i18n/index.js +++ b/src/i18n/index.js @@ -1,2 +1,9 @@ +import esMessages from './messages/es_419.json'; + // Placeholder be overridden by `make pull_translations` -export default []; +const messages = { + 'es-419': esMessages, + es: esMessages, +} + +export default messages; diff --git a/src/i18n/messages/es_419.json b/src/i18n/messages/es_419.json new file mode 100644 index 00000000..fa173649 --- /dev/null +++ b/src/i18n/messages/es_419.json @@ -0,0 +1,3 @@ +{ + "login.form.heading.1": "Iniciar sesión" +}