From dbbd493bfe5f3004beb5349f29623c237ba049e8 Mon Sep 17 00:00:00 2001 From: "Zhou (Link) Fang" <43075439+linkfang@users.noreply.github.com> Date: Thu, 26 Aug 2021 10:30:19 -0400 Subject: [PATCH 01/14] Fixed the 500 error issue (#284) --- .../src/components/UIComponents/FormPreprocess/FormChooser.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/www/src/components/UIComponents/FormPreprocess/FormChooser.js b/src/main/www/src/components/UIComponents/FormPreprocess/FormChooser.js index 52973c41..e2a29719 100644 --- a/src/main/www/src/components/UIComponents/FormPreprocess/FormChooser.js +++ b/src/main/www/src/components/UIComponents/FormPreprocess/FormChooser.js @@ -41,6 +41,7 @@ const FormChooser = ({ }; const handleStartNewForm = () => { + setIsStartNewForm(true); if (getCurrentMode() === MODE_REACT_API) setCurrentFormId(''); // reset the form if user has gone to a further page/step if (furthestPage.index > 0) { -- GitLab From 22cdee11c37fb76ebb2492e0766ce96ecd130568 Mon Sep 17 00:00:00 2001 From: Christopher Guindon Date: Thu, 26 Aug 2021 12:12:42 -0400 Subject: [PATCH 02/14] rename Contributing Member labvel Signed-off-by: Christopher Guindon --- .vscode/settings.json | 3 +++ src/main/www/src/Constants/Constants.js | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..11331294 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "automatic" +} \ No newline at end of file diff --git a/src/main/www/src/Constants/Constants.js b/src/main/www/src/Constants/Constants.js index 53231593..082f0143 100644 --- a/src/main/www/src/Constants/Constants.js +++ b/src/main/www/src/Constants/Constants.js @@ -57,7 +57,7 @@ export const FETCH_HEADER = { export const MEMBERSHIP_LEVELS = [ { label: 'Strategic Member', value: 'Strategic Member' }, { - label: 'Contributing Member (formerly referred to as Solutions Members)', + label: 'Contributing Member', value: 'Contributing Member', }, { label: 'Associate Member', value: 'Associate Member' }, -- GitLab From ea7fad4f41bd87719edc63648cc374716879e8f0 Mon Sep 17 00:00:00 2001 From: Martin Lowe Date: Thu, 26 Aug 2021 13:42:05 -0400 Subject: [PATCH 03/14] Add PDF to email, update email/pdf template to iron out inconsistencies (#276) * Initial commit of PDF creation. Needs some fine tuning before golive * Update of mail template to include more PDF data, formatting fixes * Add missing membershipLevel field to email/PDF * Update NOTICE file for md formatting * Fix notice with feedback from Sharon C. * Add paragraphs below TOS points in PDF template --- NOTICE.md | 7 +++ pom.xml | 23 +++++++ .../service/impl/DefaultMailerService.java | 61 ++++++++++++++++--- .../form_membership_email_web_template.html | 38 ++++++++---- 4 files changed, 109 insertions(+), 20 deletions(-) diff --git a/NOTICE.md b/NOTICE.md index e683cdc5..a59203e8 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -31,6 +31,13 @@ The project maintains the following source code repositories: ## Third-party Content +### OPEN HTML TO PDF (1.09) + +https://github.com/danfickle/openhtmltopdf/ +License: GNU Lesser General Public License (LGPL) +SPDX-License-Identifier: LGPL-2.1-only +No modifications or additions to the library have been made. License text provided through library distribution. + ### Drupal-Bootstrap (7.x-3.20) * License: The GPL License (GPL) diff --git a/pom.xml b/pom.xml index 93b5a7b3..22816a92 100644 --- a/pom.xml +++ b/pom.xml @@ -19,6 +19,7 @@ 1.13.7.Final 3.8.1 io.quarkus + 1.0.9 @@ -97,6 +98,28 @@ io.quarkus quarkus-hibernate-validator + + + + com.openhtmltopdf + openhtmltopdf-core + ${openhtml.version} + + + + + com.openhtmltopdf + openhtmltopdf-pdfbox + ${openhtml.version} + + + + + com.openhtmltopdf + openhtmltopdf-java2d + ${openhtml.version} + + io.quarkus quarkus-junit5 diff --git a/src/main/java/org/eclipsefoundation/react/service/impl/DefaultMailerService.java b/src/main/java/org/eclipsefoundation/react/service/impl/DefaultMailerService.java index c58c4cf4..d9e2aef7 100644 --- a/src/main/java/org/eclipsefoundation/react/service/impl/DefaultMailerService.java +++ b/src/main/java/org/eclipsefoundation/react/service/impl/DefaultMailerService.java @@ -1,8 +1,13 @@ package org.eclipsefoundation.react.service.impl; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; +import java.util.UUID; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; @@ -13,6 +18,9 @@ import org.eclipsefoundation.react.service.MailerService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.openhtmltopdf.outputdevice.helper.BaseRendererBuilder.PageSizeUnits; +import com.openhtmltopdf.pdfboxout.PdfRendererBuilder; + import io.quarkus.mailer.Mail; import io.quarkus.mailer.Mailer; import io.quarkus.qute.Location; @@ -31,12 +39,19 @@ import io.smallrye.jwt.auth.principal.DefaultJWTCallerPrincipal; public class DefaultMailerService implements MailerService { public static final Logger LOGGER = LoggerFactory.getLogger(DefaultMailerService.class); + private static final String EMAIL_INCLUDE_PREAMBLE_VAR = "includePreamble"; + private static final String EMAIL_DATA_VAR = "data"; + private static final String EMAIL_NOW_VAR = "now"; + private static final String EMAIL_NAME_VAR = "name"; + @ConfigProperty(name = "eclipse.mailer.membership.inbox") String membershipMailbox; @ConfigProperty(name = "eclipse.mailer.membership.author-message.bcc") Optional> authorMessageMailboxBcc; @ConfigProperty(name = "eclipse.mailer.membership.membership-message.bcc") Optional> membershipMessageMailboxBcc; + @ConfigProperty(name = "eclipse.mailer.membership.doc-storage-root", defaultValue = "/tmp") + String temporaryDocumentStorage; @Inject SecurityIdentity ident; @@ -79,12 +94,21 @@ public class DefaultMailerService implements MailerService { throw new IllegalStateException( "Could not find a fully complete form for form with ID '" + data.form.getId() + "'"); } - Mail m = getMail(membershipMailbox, "New Request to join working group(s) - " - + generateName((DefaultJWTCallerPrincipal) ident.getPrincipal()), data, false); + DefaultJWTCallerPrincipal defaultPrin = (DefaultJWTCallerPrincipal) ident.getPrincipal(); + Mail m = getMail(membershipMailbox, "New Request to join working group(s) - " + generateName(defaultPrin), data, + false); // add BCC if set if (!membershipMessageMailboxBcc.isEmpty()) { m.setBcc(membershipMessageMailboxBcc.get()); } + // add the PDF attachment + m.addAttachment("membership-enrollment-" + generateName(defaultPrin).toLowerCase().replace(" ", "-") + ".pdf", + renderHTMLPDF( + membershipTemplateWeb + .data(EMAIL_DATA_VAR, data, EMAIL_NAME_VAR, generateName(defaultPrin), EMAIL_NOW_VAR, + LocalDateTime.now(), EMAIL_INCLUDE_PREAMBLE_VAR, false, "isPDF", true) + .render()), + "application/pdf"); mailer.send(m); } @@ -101,15 +125,36 @@ public class DefaultMailerService implements MailerService { private Mail getMail(String recipient, String subject, MailerData data, boolean includePreamble) { String name = generateName((DefaultJWTCallerPrincipal) ident.getPrincipal()); // generate the mail message, sending the messsage to the membershipMailbox - Mail m = Mail.withHtml(recipient, subject, membershipTemplateWeb - .data("data", data, "name", name, "now", LocalDateTime.now(), "includePreamble", includePreamble) - .render()); - m.setText(membershipTemplate - .data("data", data, "name", name, "now", LocalDateTime.now(), "includePreamble", includePreamble) - .render()); + Mail m = Mail.withHtml(recipient, subject, membershipTemplateWeb.data(EMAIL_DATA_VAR, data, EMAIL_NAME_VAR, + name, EMAIL_NOW_VAR, LocalDateTime.now(), EMAIL_INCLUDE_PREAMBLE_VAR, includePreamble).render()); + m.setText(membershipTemplate.data(EMAIL_DATA_VAR, data, EMAIL_NAME_VAR, name, EMAIL_NOW_VAR, + LocalDateTime.now(), EMAIL_INCLUDE_PREAMBLE_VAR, includePreamble).render()); return m; } + /** + * Render the PDF document using HTML generated by the Qute template engine. + * + * @param html the HTML for the PDF document. + * @return the file that represents the document. This should be in a temporary directory so that it gets cleaned on + * occasion. + */ + private File renderHTMLPDF(String html) { + // create a unique file name for temporary storage + File f = new File(temporaryDocumentStorage + '/' + UUID.randomUUID().toString() + ".pdf"); + try (OutputStream os = new FileOutputStream(f)) { + PdfRendererBuilder builder = new PdfRendererBuilder(); + builder.withHtmlContent(html, temporaryDocumentStorage); + // using a4 measurements + builder.useDefaultPageSize(210, 297, PageSizeUnits.MM); + builder.toStream(os); + builder.run(); + } catch (IOException e) { + throw new RuntimeException("Could not build PDF document", e); + } + return f; + } + private String generateName(DefaultJWTCallerPrincipal defaultPrin) { return new StringBuilder().append((String) defaultPrin.getClaim("given_name")).append(" ") .append((String) defaultPrin.getClaim("family_name")).toString(); diff --git a/src/main/resources/templates/emails/form_membership_email_web_template.html b/src/main/resources/templates/emails/form_membership_email_web_template.html index 59f44740..28ddb50c 100644 --- a/src/main/resources/templates/emails/form_membership_email_web_template.html +++ b/src/main/resources/templates/emails/form_membership_email_web_template.html @@ -1,7 +1,8 @@ -
-
+
+
-

Eclipse Foundation AISBL Membership Application date submitted: {now}

+

Eclipse Foundation AISBL Membership Application

+

Date submitted: {time:format(now,'d MMM uuuu, HH:mm')}

{#if includePreamble}

Dear {name},

Thank you for submitting the member enrollment form on behalf of your organization. Our team will review your application and follow up within 2 business days.

@@ -9,16 +10,17 @@

Best regards,

Eclipse Foundation Membership Coordination

{/if} -

New form submission by: {name} ({data.form.userID})

+

Form submission by: {name} ({data.form.userID})

Organization

-

Name: {data.org.legalName}

-

Aggregate Revenue: {data.org.aggregateRevenue}

-

Employee count: {data.org.employeeCount}

+

Name: {data.org.legalName}

+

Aggregate Revenue: {data.org.aggregateRevenue}

+

Employee Count: {data.org.employeeCount}

Organization Type: {data.org.organizationType}

-

Twitter: {data.org.twitterHandle}

-

Requires purchase order: {data.form.purchaseOrderRequired}

-

VAT number: {data.form.vatNumber}

-

VAT Registration country: {data.form.registrationCountry}

+

Twitter: {data.org.twitterHandle}

+

Requires Purchase Order: {data.form.purchaseOrderRequired}

+

VAT Number: {data.form.vatNumber}

+

VAT Registration Country: {data.form.registrationCountry}

+

Membership Level: {data.form.membershipLevel}

Address

@@ -70,7 +72,19 @@ {/for} -


+ {#if isPDF} +

We thank you for completing this Member Application Form.

+

As a new Member:

+
    +
  1. You agree to publicly support the Eclipse Foundation and its Purpose.
  2. +
  3. You acknowledge your commitment in principle to comply with the Bylaws, the Internal Rules, the Eclipse Foundation Antitrust Policy, IP Policy, and any and all additional policies, procedures and other governing rules of the Eclipse Foundation.
  4. +
  5. You agree to provide Eclipse Foundation with your logo (or instructions to obtain your logo) in accordance with Section 2.3 of the Eclipse Foundation Membership Agreement. When providing your logo, be sure to include a reference or link to any logo and trademark usage guidelines you have.
    + Our Membership Coordination team will work with you to complete this after your Membership Application is processed.
  6. +
+

Thank you for completing the Membership Application Process. This PDF captures the information you have provided to us. Please review this information as it becomes a part of your formal application to the Eclipse Foundation.

+

Should you wish to update any of the information, please reach out to our Membership team at membership.coordination@eclipse-foundation.org

+ {/if} +

This is an automatic message from https://membership.eclipse.org

Twitter: @EclipseFdn

-- GitLab From 8ccd0b7831d944419923933ed0d0a5807201ed8f Mon Sep 17 00:00:00 2001 From: Christopher Guindon Date: Thu, 26 Aug 2021 14:11:11 -0400 Subject: [PATCH 04/14] 502 Bad Gateway on large requests through API, too small buffers #285 (#289) * 502 Bad Gateway on large requests through API, too small buffers #285 * Update nginx.conf --- config/nginx/nginx.conf | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/config/nginx/nginx.conf b/config/nginx/nginx.conf index 6d99167c..fcde2335 100644 --- a/config/nginx/nginx.conf +++ b/config/nginx/nginx.conf @@ -5,6 +5,12 @@ server { client_max_body_size 16m; client_body_buffer_size 128k; + + # proxy buffering configuration + # https://stackoverflow.com/a/27551259/8538422 + proxy_buffer_size 128k; + proxy_buffers 4 256k; + proxy_busy_buffers_size 256k; location /api { # don't cache it @@ -31,4 +37,4 @@ server { index index.html index.htm; try_files $uri $uri/ /index.html =404; } -} \ No newline at end of file +} -- GitLab From ccf3a4579c9c8f39125da01f2a3532a359c18a83 Mon Sep 17 00:00:00 2001 From: "Zhou (Link) Fang" <43075439+linkfang@users.noreply.github.com> Date: Thu, 26 Aug 2021 14:17:55 -0400 Subject: [PATCH 05/14] Updated content on sign in page (#282) --- src/main/www/src/App.css | 4 ++- .../components/Application/SignIn/SignIn.js | 19 ++++------- .../Application/SignIn/SignInIntroduction.js | 32 +++++++++++-------- .../FormPreprocess/FormChooser.js | 4 +-- .../UIComponents/Loading/Loading.js | 4 +-- src/main/www/src/less/App.less | 5 ++- 6 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/main/www/src/App.css b/src/main/www/src/App.css index ab73c8ba..6c95caf5 100644 --- a/src/main/www/src/App.css +++ b/src/main/www/src/App.css @@ -41,6 +41,8 @@ html { display: flex; align-items: center; justify-content: center; +} +.eclipsefdn-membership-webform .loadingIcon { margin-top: 5rem; margin-bottom: 3rem; } @@ -56,7 +58,7 @@ html { border-color: #ff0000; } .eclipsefdn-membership-webform .btn { - margin: 0 10px; + margin: 10px; border-radius: 5px; } .eclipsefdn-membership-webform .button-container { diff --git a/src/main/www/src/components/Application/SignIn/SignIn.js b/src/main/www/src/components/Application/SignIn/SignIn.js index baeb4263..defb3da3 100644 --- a/src/main/www/src/components/Application/SignIn/SignIn.js +++ b/src/main/www/src/components/Application/SignIn/SignIn.js @@ -60,26 +60,21 @@ class SignIn extends React.Component { this.context.needLoadingSignIn ? ( ) : ( -
+
+

+ Get started by logging in with your Eclipse Foundation account: +

{getCurrentMode() === MODE_REACT_ONLY && ( - )} {getCurrentMode() === MODE_REACT_API && ( - - Sign In + + Log in )} diff --git a/src/main/www/src/components/Application/SignIn/SignInIntroduction.js b/src/main/www/src/components/Application/SignIn/SignInIntroduction.js index b4f4d5fe..2ebd1369 100644 --- a/src/main/www/src/components/Application/SignIn/SignInIntroduction.js +++ b/src/main/www/src/components/Application/SignIn/SignInIntroduction.js @@ -1,21 +1,27 @@ const SignInIntroduction = () => { return ( -
-
+
+
+ arrows-icons +
+
-

- Please complete the Member Application Form as part of the overall - membership application and enrolment process. Note that completion of - this Form is a required formal step in the Membership Application - Process. + Once you complete and submit this Application Form, we will forward the various legal agreements for + electronic execution, so please be sure to review these legal documents in advance. For more information, + please see{' '} + + here + + .

diff --git a/src/main/www/src/components/UIComponents/FormPreprocess/FormChooser.js b/src/main/www/src/components/UIComponents/FormPreprocess/FormChooser.js index e2a29719..7aa967c9 100644 --- a/src/main/www/src/components/UIComponents/FormPreprocess/FormChooser.js +++ b/src/main/www/src/components/UIComponents/FormPreprocess/FormChooser.js @@ -14,7 +14,7 @@ import { import { useCallback, useContext, useEffect, useState } from 'react'; import Loading from '../Loading/Loading'; const styles = { - marginBottom: '20px', + marginBottom: '30px', textAlign: 'center', }; @@ -100,7 +100,7 @@ const FormChooser = ({ ) : (
-

+

Welcome back! You can continue the application you previously started or start a new application.

diff --git a/src/main/www/src/components/UIComponents/Loading/Loading.js b/src/main/www/src/components/UIComponents/Loading/Loading.js index aa9d3bb3..97cabae7 100644 --- a/src/main/www/src/components/UIComponents/Loading/Loading.js +++ b/src/main/www/src/components/UIComponents/Loading/Loading.js @@ -1,8 +1,6 @@ -import React from 'react'; - const Loading = () => { return ( -
+
); diff --git a/src/main/www/src/less/App.less b/src/main/www/src/less/App.less index 912afcee..7a8d1fe6 100644 --- a/src/main/www/src/less/App.less +++ b/src/main/www/src/less/App.less @@ -96,6 +96,9 @@ html { display: flex; align-items: center; justify-content: center; + } + + .loadingIcon { margin-top: 5rem; margin-bottom: 3rem; } @@ -115,7 +118,7 @@ html { } .btn { - margin: 0 10px; + margin: 10px; border-radius: @border-radius; } -- GitLab From 41b8dafc1e16a654ee69836af86fc8ca0cc8fbfc Mon Sep 17 00:00:00 2001 From: "Zhou (Link) Fang" <43075439+linkfang@users.noreply.github.com> Date: Thu, 26 Aug 2021 14:20:10 -0400 Subject: [PATCH 06/14] Updated the content on confirmation step (#281) --- .../SubmitSuccess/SubmitSuccess.js | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/src/main/www/src/components/Application/SubmitSuccess/SubmitSuccess.js b/src/main/www/src/components/Application/SubmitSuccess/SubmitSuccess.js index 3d25d2ef..26c7a4c2 100644 --- a/src/main/www/src/components/Application/SubmitSuccess/SubmitSuccess.js +++ b/src/main/www/src/components/Application/SubmitSuccess/SubmitSuccess.js @@ -13,14 +13,49 @@ const SubmitSuccess = () => { return ( <>

Confirmation message on submission:

-

We thank you for completing the membership application.

+

We thank you for completing the application process.

+

As next steps,

+
    +
  1. +

    + You will receive an automated email capturing the information you have provided. Please review this + information, and let us know of any errors or changes required by emailing{' '} + + membership.coordination@eclipse-foundation.org + + . +

    +
  2. +
  3. +

    + Within the next two business days, our membership coordination team will send via HelloSign’s document + signature system the membership documents to be executed. +

      +
    1. + If you are the signing authority indicated on the application, then the documents will be sent directly + to you. +
    2. +
    3. + If you indicated someone else in your organization is the signing authority, our membership coordination + team will let you know of the status of the signing process - but the documents will be sent directly to + the signing authority. +
    4. +
    +

    +
  4. +
  5. + Once the membership document(s) are executed by your organization, the Eclipse Foundation’s Executive Director + will countersign and the completed documents will be returned to you by our membership coordination team. They + will also begin the ongboarding walk you and your other team members through our onboarding process. +
  6. +

- Our membership coordination team will send a ready to sign membership - documents to the signing authority. If you have not received the - ready-to-sign agreement within 2 business days, please contact{' '} + If you have any questions, or have not received notification of the signing process being underway after 2 + business days, please contact{' '} membership.coordination@eclipse-foundation.org + .

); -- GitLab From 4e7dda1fb4e589ed9f031f58b8e42c6124074b36 Mon Sep 17 00:00:00 2001 From: "Zhou (Link) Fang" <43075439+linkfang@users.noreply.github.com> Date: Thu, 26 Aug 2021 14:31:16 -0400 Subject: [PATCH 07/14] Fix data update bug with stepper (#280) * Updated the stepper * updated navigation logic * Updated navigation logic for submitForm func --- src/main/www/src/App.css | 1 + src/main/www/src/Constants/Constants.js | 10 +- src/main/www/src/Utils/formFunctionHelpers.js | 88 +----- .../src/components/Application/Application.js | 289 +++++++++--------- .../CompanyInformation/CompanyInformation.js | 1 - .../components/UIComponents/Steppers/Step.js | 57 +++- src/main/www/src/less/App.less | 1 + 7 files changed, 202 insertions(+), 245 deletions(-) diff --git a/src/main/www/src/App.css b/src/main/www/src/App.css index 6c95caf5..0b0ac524 100644 --- a/src/main/www/src/App.css +++ b/src/main/www/src/App.css @@ -118,6 +118,7 @@ html { justify-content: center; position: relative; padding-top: 30px; + cursor: pointer; } .eclipsefdn-membership-webform .step a { text-decoration: none; diff --git a/src/main/www/src/Constants/Constants.js b/src/main/www/src/Constants/Constants.js index 082f0143..59dd315a 100644 --- a/src/main/www/src/Constants/Constants.js +++ b/src/main/www/src/Constants/Constants.js @@ -64,11 +64,11 @@ export const MEMBERSHIP_LEVELS = [ ]; export const PAGE_STEP = [ - { props: { label: COMPANY_INFORMATION, pathName: '/company-info' } }, - { props: { label: MEMBERSHIP_LEVEL, pathName: '/membership-level' } }, - { props: { label: WORKING_GROUPS, pathName: '/working-groups' } }, - { props: { label: SIGNING_AUTHORITY, pathName: '/signing-authority' } }, - { props: { label: REVIEW, pathName: '/review' } }, + { label: COMPANY_INFORMATION, pathName: '/company-info' }, + { label: MEMBERSHIP_LEVEL, pathName: '/membership-level' }, + { label: WORKING_GROUPS, pathName: '/working-groups' }, + { label: SIGNING_AUTHORITY, pathName: '/signing-authority' }, + { label: REVIEW, pathName: '/review' }, ]; export const CONTACT_TYPE = { diff --git a/src/main/www/src/Utils/formFunctionHelpers.js b/src/main/www/src/Utils/formFunctionHelpers.js index 86d78e28..d958786c 100644 --- a/src/main/www/src/Utils/formFunctionHelpers.js +++ b/src/main/www/src/Utils/formFunctionHelpers.js @@ -7,7 +7,6 @@ import { getCurrentMode, MODE_REACT_ONLY, MODE_REACT_API, - PATH_NAME_ARRAY, HAS_TOKEN_EXPIRED, } from '../Constants/Constants'; @@ -329,27 +328,14 @@ export function matchWGFieldsToBackend(eachWorkingGroupData, formId) { * @param formId - Form Id fetched from the server, sotored in membership context, used for calling APIs * @param userId - User Id fetched from the server when sign in, sotored in membership context, used for calling APIs */ -export async function executeSendDataByStep( - step, - formData, - formId, - userId, - goToNextStep, - setFieldValueObj -) { - const goToNextStepObj = { - method: goToNextStep, - stepNum: step, - pathName: PATH_NAME_ARRAY[step], - }; +export async function executeSendDataByStep(step, formData, formId, userId, setFieldValueObj) { switch (step) { case 1: - // only need 1 goToNextStepObj in "case 1", or it would execute it 5 times. callSendData( formId, END_POINT.organizations, matchCompanyFieldsToBackend(formData.organization, formId), - goToNextStepObj, + step, { fieldName: setFieldValueObj.fieldName.organization, method: setFieldValueObj.method, @@ -358,12 +344,8 @@ export async function executeSendDataByStep( callSendData( formId, END_POINT.contacts, - matchContactFieldsToBackend( - formData.representative.member, - CONTACT_TYPE.COMPANY, - formId - ), - '', + matchContactFieldsToBackend(formData.representative.member, CONTACT_TYPE.COMPANY, formId), + step, { fieldName: setFieldValueObj.fieldName.member, method: setFieldValueObj.method, @@ -372,12 +354,8 @@ export async function executeSendDataByStep( callSendData( formId, END_POINT.contacts, - matchContactFieldsToBackend( - formData.representative.marketing, - CONTACT_TYPE.MARKETING, - formId - ), - '', + matchContactFieldsToBackend(formData.representative.marketing, CONTACT_TYPE.MARKETING, formId), + step, { fieldName: setFieldValueObj.fieldName.marketing, method: setFieldValueObj.method, @@ -386,32 +364,18 @@ export async function executeSendDataByStep( callSendData( formId, END_POINT.contacts, - matchContactFieldsToBackend( - formData.representative.accounting, - CONTACT_TYPE.ACCOUNTING, - formId - ), - '', + matchContactFieldsToBackend(formData.representative.accounting, CONTACT_TYPE.ACCOUNTING, formId), + step, { fieldName: setFieldValueObj.fieldName.accounting, method: setFieldValueObj.method, } ); - callSendData( - formId, - '', - matchMembershipLevelFieldsToBackend(formData, formId, userId), - '' - ); + callSendData(formId, '', matchMembershipLevelFieldsToBackend(formData, formId, userId), ''); break; case 2: - callSendData( - formId, - '', - matchMembershipLevelFieldsToBackend(formData, formId, userId), - goToNextStepObj - ); + callSendData(formId, '', matchMembershipLevelFieldsToBackend(formData, formId, userId), step); break; case 3: @@ -420,7 +384,7 @@ export async function executeSendDataByStep( formId, END_POINT.working_groups, matchWGFieldsToBackend(item, formId), - goToNextStepObj, + step, setFieldValueObj, index ); @@ -431,24 +395,14 @@ export async function executeSendDataByStep( callSendData( formId, END_POINT.contacts, - matchContactFieldsToBackend( - formData.signingAuthorityRepresentative, - CONTACT_TYPE.SIGNING, - formId - ), - goToNextStepObj, + matchContactFieldsToBackend(formData.signingAuthorityRepresentative, CONTACT_TYPE.SIGNING, formId), + step, setFieldValueObj ); break; case 5: - callSendData( - formId, - END_POINT.complete, - false, - goToNextStepObj, - setFieldValueObj - ); + callSendData(formId, END_POINT.complete, false, step, setFieldValueObj); break; default: @@ -468,7 +422,7 @@ function callSendData( formId, endpoint = '', dataBody, - goToNextStepObj, + stepNum, setFieldValueObj, index ) { @@ -490,9 +444,6 @@ function callSendData( if (getCurrentMode() === MODE_REACT_ONLY) { console.log(`You called ${url} with Method ${method} and data body is:`); console.log(JSON.stringify(dataBody)); - if (goToNextStepObj) { - goToNextStepObj.method(goToNextStepObj.stepNum, goToNextStepObj.pathName); - } } if (getCurrentMode() === MODE_REACT_API) { @@ -502,7 +453,7 @@ function callSendData( body: JSON.stringify(dataBody), }) .then((res) => { - if (goToNextStepObj.stepNum === 5) { + if (stepNum === 5) { if (res.ok) return res; } else { if (res.ok) return res.json(); @@ -573,13 +524,6 @@ function callSendData( break; } } - - if (goToNextStepObj) { - goToNextStepObj.method( - goToNextStepObj.stepNum, - goToNextStepObj.pathName - ); - } }) .catch((err) => { console.log(err); diff --git a/src/main/www/src/components/Application/Application.js b/src/main/www/src/components/Application/Application.js index d2bf601e..0d2be384 100644 --- a/src/main/www/src/components/Application/Application.js +++ b/src/main/www/src/components/Application/Application.js @@ -56,175 +56,159 @@ export default function Application() { '', currentFormId, currentUser.name, - goToNextStep, '' ); + goToNextStep(5, '/submitted'); }; + const submitCompanyInfo = (isUsingStepper) => { + const values = formikCompanyInfo.values; + // update the organization values + const organization = values.organization; + const representative = values.representative; + const purchasingAndVAT = values.purchasingAndVAT; + const membershipLevel = values.membershipLevel; + const membershipLevelLabel = values['membershipLevel-label']; + const signingAuthorityRepresentative = values.signingAuthorityRepresentative; + + const theNewValue = { + ...updatedFormValues, + organization, + representative, + purchasingAndVAT, + membershipLevel, + 'membershipLevel-label': membershipLevelLabel, + signingAuthorityRepresentative: signingAuthorityRepresentative, + }; + setUpdatedFormValues(theNewValue); + console.log('updated company info: ', values); + + const valueForMembershipLevelFormik = [ + { field: 'purchasingAndVAT', value: purchasingAndVAT }, + { field: 'membershipLevel', value: membershipLevel }, + { + field: 'membershipLevel-label', + value: membershipLevelLabel?.label ? membershipLevelLabel : null, + }, + ]; + // set valueToUpdateFormik to membershipLevel formik to make sure the value is up to date + updateMembershipLevelForm(valueForMembershipLevelFormik); + + const valueForSigningAuthorityFormik = [ + { + field: 'signingAuthorityRepresentative', + value: signingAuthorityRepresentative, + }, + ]; + updateSigningAuthorityForm(valueForSigningAuthorityFormik); + + const setFieldValueObj = { + fieldName: { + organization: 'organization', + member: 'representative.member', + accounting: 'representative.accounting', + marketing: 'representative.marketing', + }, + method: formikCompanyInfo.setFieldValue, + }; + + executeSendDataByStep(1, theNewValue, currentFormId, currentUser.name, setFieldValueObj); + // Only need to call goToNextStep when is not using stepper + !isUsingStepper && goToNextStep(1, '/membership-level'); + }; const formikCompanyInfo = useFormik({ initialValues: initialValues, validationSchema: validationSchema[0], - onSubmit: (values) => { - // update the organization values - const organization = values.organization; - const representative = values.representative; - const purchasingAndVAT = values.purchasingAndVAT; - const membershipLevel = values.membershipLevel; - const membershipLevelLabel = values['membershipLevel-label']; - const signingAuthorityRepresentative = - values.signingAuthorityRepresentative; - - const theNewValue = { - ...updatedFormValues, - organization, - representative, - purchasingAndVAT, - membershipLevel, - 'membershipLevel-label': membershipLevelLabel, - signingAuthorityRepresentative: signingAuthorityRepresentative, - }; - setUpdatedFormValues(theNewValue); - console.log('updated company info: ', values); - - const valueForMembershipLevelFormik = [ - { field: 'purchasingAndVAT', value: purchasingAndVAT }, - { field: 'membershipLevel', value: membershipLevel }, - { - field: 'membershipLevel-label', - value: membershipLevelLabel?.label ? membershipLevelLabel : null, - }, - ]; - // set valueToUpdateFormik to membershipLevel formik to make sure the value is up to date - updateMembershipLevelForm(valueForMembershipLevelFormik); - - const valueForSigningAuthorityFormik = [ - { - field: 'signingAuthorityRepresentative', - value: signingAuthorityRepresentative, - }, - ]; - updateSigningAuthorityForm(valueForSigningAuthorityFormik); - - const setFieldValueObj = { - fieldName: { - organization: 'organization', - member: 'representative.member', - accounting: 'representative.accounting', - marketing: 'representative.marketing', - }, - method: formikCompanyInfo.setFieldValue, - }; - executeSendDataByStep( - 1, - theNewValue, - currentFormId, - currentUser.name, - goToNextStep, - setFieldValueObj - ); - }, + onSubmit: () => submitCompanyInfo(), }); + const submitMembershipLevel = (isUsingStepper) => { + const values = formikMembershipLevel.values; + // update the membershipLevel values + const membershipLevel = values.membershipLevel; + const membershipLevelLabel = values['membershipLevel-label']; + setUpdatedFormValues({ + ...updatedFormValues, + membershipLevel, + 'membershipLevel-label': membershipLevelLabel, + }); + console.log('updated membership level: ', values); + + const valueToUpdateFormik = [ + { field: 'membershipLevel', value: membershipLevel }, + { field: 'membershipLevel-label', value: membershipLevelLabel }, + ]; + // set valueToUpdateFormik to CompanyInfo formik to make sure the value is up to date + updateCompanyInfoForm(valueToUpdateFormik); + + executeSendDataByStep(2, values, currentFormId, currentUser.name); + !isUsingStepper && goToNextStep(2, '/working-groups'); + }; const formikMembershipLevel = useFormik({ initialValues: initialValues, validationSchema: validationSchema[1], - onSubmit: (values) => { - // update the membershipLevel values - const membershipLevel = values.membershipLevel; - const membershipLevelLabel = values['membershipLevel-label']; - setUpdatedFormValues({ - ...updatedFormValues, - membershipLevel, - 'membershipLevel-label': membershipLevelLabel, - }); - console.log('updated membership level: ', values); - - const valueToUpdateFormik = [ - { field: 'membershipLevel', value: membershipLevel }, - { field: 'membershipLevel-label', value: membershipLevelLabel }, - ]; - // set valueToUpdateFormik to CompanyInfo formik to make sure the value is up to date - updateCompanyInfoForm(valueToUpdateFormik); - - executeSendDataByStep( - 2, - values, - currentFormId, - currentUser.name, - goToNextStep - ); - }, + onSubmit: () => submitMembershipLevel(), }); + const submitWorkingGroups = (isUsingStepper) => { + const values = formikWorkingGroups.values; + // update the workingGroups values + const workingGroups = values.workingGroups; + setUpdatedFormValues({ ...updatedFormValues, workingGroups }); + console.log('updated working groups: ', values); + + if (values.isJoiningWG) { + // If the user is joining at least 1 wg, then make related API call + const setFieldValueObj = { + fieldName: 'workingGroups', + method: formikWorkingGroups.setFieldValue, + }; + + executeSendDataByStep(3, values, currentFormId, currentUser.name, setFieldValueObj); + !isUsingStepper && goToNextStep(3, '/signing-authority'); + } else if (!isUsingStepper) { + // If the user is NOT using stepper and NOT joining any wg, then go to next page directly + goToNextStep(3, '/signing-authority'); + } + }; const formikWorkingGroups = useFormik({ initialValues: initialValues, validationSchema: validationSchema[2], - onSubmit: (values) => { - // update the workingGroups values - const workingGroups = values.workingGroups; - setUpdatedFormValues({ ...updatedFormValues, workingGroups }); - console.log('updated working groups: ', values); - - if (values.isJoiningWG){ - // If the user is joining at least 1 wg, then make related API call - const setFieldValueObj = { - fieldName: 'workingGroups', - method: formikWorkingGroups.setFieldValue, - }; - - executeSendDataByStep( - 3, - values, - currentFormId, - currentUser.name, - goToNextStep, - setFieldValueObj - ); - } else { - // If the user is NOT joining any wg, then go to next page directly - goToNextStep(3, '/signing-authority') - } - - }, + onSubmit: () => submitWorkingGroups(), }); + const submitSigningAuthority = (isUsingStepper) => { + const values = formikSigningAuthority.values; + // update the signingAuthorityRepresentative values + const signingAuthorityRepresentative = values.signingAuthorityRepresentative; + setUpdatedFormValues({ + ...updatedFormValues, + signingAuthorityRepresentative, + }); + console.log('updated SigningAuthority: ', values); + + const valueToUpdateFormik = [ + { + field: 'signingAuthorityRepresentative', + value: signingAuthorityRepresentative, + }, + ]; + // set valueToUpdateFormik to CompanyInfo formik to make sure the value is up to date + updateCompanyInfoForm(valueToUpdateFormik); + const setFieldValueObj = { + fieldName: 'signingAuthorityRepresentative', + method: { + signingAuthority: formikSigningAuthority.setFieldValue, + companyInfo: formikCompanyInfo.setFieldValue, + }, + }; + executeSendDataByStep(4, values, currentFormId, currentUser.name, setFieldValueObj); + !isUsingStepper && goToNextStep(4, '/review'); + }; const formikSigningAuthority = useFormik({ initialValues: initialValues, validationSchema: validationSchema[3], - onSubmit: (values) => { - // update the signingAuthorityRepresentative values - const signingAuthorityRepresentative = - values.signingAuthorityRepresentative; - setUpdatedFormValues({ - ...updatedFormValues, - signingAuthorityRepresentative, - }); - console.log('updated SigningAuthority: ', values); - - const valueToUpdateFormik = [ - { - field: 'signingAuthorityRepresentative', - value: signingAuthorityRepresentative, - }, - ]; - // set valueToUpdateFormik to CompanyInfo formik to make sure the value is up to date - updateCompanyInfoForm(valueToUpdateFormik); - const setFieldValueObj = { - fieldName: 'signingAuthorityRepresentative', - method: { - signingAuthority: formikSigningAuthority.setFieldValue, - companyInfo: formikCompanyInfo.setFieldValue, - }, - }; - executeSendDataByStep( - 4, - values, - currentFormId, - currentUser.name, - goToNextStep, - setFieldValueObj - ); - }, + onSubmit: () => submitSigningAuthority(), }); const handleLoginExpired = useCallback(() => { @@ -248,16 +232,19 @@ export default function Application() { // generate the step options above the form const renderStepper = () => (
- + {PAGE_STEP.map((pageStep, index) => { return ( ); })} diff --git a/src/main/www/src/components/Application/CompanyInformation/CompanyInformation.js b/src/main/www/src/components/Application/CompanyInformation/CompanyInformation.js index 4f5691a1..c1bc4cb6 100644 --- a/src/main/www/src/components/Application/CompanyInformation/CompanyInformation.js +++ b/src/main/www/src/components/Application/CompanyInformation/CompanyInformation.js @@ -224,7 +224,6 @@ const CompanyInformation = ({ formik, isStartNewForm }) => { ); diff --git a/src/main/www/src/components/UIComponents/Steppers/Step.js b/src/main/www/src/components/UIComponents/Steppers/Step.js index daa718b3..d534febd 100644 --- a/src/main/www/src/components/UIComponents/Steppers/Step.js +++ b/src/main/www/src/components/UIComponents/Steppers/Step.js @@ -1,4 +1,7 @@ -import { NavLink, useRouteMatch } from 'react-router-dom'; +import { useContext } from 'react'; +import { useHistory } from 'react-router-dom'; +import { useRouteMatch } from 'react-router-dom'; +import MembershipContext from '../../../Context/MembershipContext'; /** * Props: @@ -15,24 +18,46 @@ import { NavLink, useRouteMatch } from 'react-router-dom'; * - formRef: Passed from FormikStepper. Can use Formik API * **/ -const Step = (props) => { - const { index, title, pathName } = props; +const Step = ({ + index, + title, + pathName, + submitCompanyInfo, + submitMembershipLevel, + submitWorkingGroups, + submitSigningAuthority, +}) => { const isActive = useRouteMatch(pathName); - + const history = useHistory(); + const { furthestPage } = useContext(MembershipContext); + const handleSubmit = () => { + // Only call submit func when user can navigate using stepper + switch (window.location.hash) { + case '#company-info': + furthestPage.index > 1 && submitCompanyInfo(true); + break; + case '#membership-level': + furthestPage.index > 2 && submitMembershipLevel(true); + break; + case '#working-groups': + furthestPage.index > 3 && submitWorkingGroups(true); + break; + case '#signing-authority': + furthestPage.index > 4 && submitSigningAuthority(true); + break; + default: + break; + } + history.push(pathName); + }; return ( -
- - {index + 2} -
-
- {title} -
+
+ {index + 2} +
+
+ {title}
- +
); }; diff --git a/src/main/www/src/less/App.less b/src/main/www/src/less/App.less index 7a8d1fe6..ccfa40c8 100644 --- a/src/main/www/src/less/App.less +++ b/src/main/www/src/less/App.less @@ -190,6 +190,7 @@ html { justify-content: center; position: relative; padding-top: 30px; + cursor: pointer; } a { text-decoration: none; -- GitLab From e35b6579fd21b4dfe2771ba9e0ca6eddfc9335e1 Mon Sep 17 00:00:00 2001 From: Martin Lowe Date: Thu, 26 Aug 2021 14:33:53 -0400 Subject: [PATCH 08/14] Patch terminology around form name for emails + pdf (#291) --- .../templates/emails/form_membership_email_template.txt | 2 +- .../templates/emails/form_membership_email_web_template.html | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/resources/templates/emails/form_membership_email_template.txt b/src/main/resources/templates/emails/form_membership_email_template.txt index 688d9c1b..14bee320 100644 --- a/src/main/resources/templates/emails/form_membership_email_template.txt +++ b/src/main/resources/templates/emails/form_membership_email_template.txt @@ -2,7 +2,7 @@ Eclipse Foundation AISBL Membership Application date submitted: {now} {#if includePreamble} Dear {name}, -Thank you for submitting the member enrollment form on behalf of your organization. Our team will review your application and follow up within 2 business days. +Thank you for submitting the Membership Application Form on behalf of your organization. Our team will review your application and follow up within 2 business days. Meanwhile, if you have any questions, please reach out to us at membership.coordination@eclipse-foundation.org. Best regards, diff --git a/src/main/resources/templates/emails/form_membership_email_web_template.html b/src/main/resources/templates/emails/form_membership_email_web_template.html index 28ddb50c..2f98f725 100644 --- a/src/main/resources/templates/emails/form_membership_email_web_template.html +++ b/src/main/resources/templates/emails/form_membership_email_web_template.html @@ -5,7 +5,7 @@

Date submitted: {time:format(now,'d MMM uuuu, HH:mm')}

{#if includePreamble}

Dear {name},

-

Thank you for submitting the member enrollment form on behalf of your organization. Our team will review your application and follow up within 2 business days.

+

Thank you for submitting the Membership Application Form on behalf of your organization. Our team will review your application and follow up within 2 business days.

Meanwhile, if you have any questions, please reach out to us at membership.coordination@eclipse-foundation.org.

Best regards,

Eclipse Foundation Membership Coordination

@@ -73,7 +73,6 @@ {#if isPDF} -

We thank you for completing this Member Application Form.

As a new Member:

  1. You agree to publicly support the Eclipse Foundation and its Purpose.
  2. -- GitLab From bd39b29beafbeec8f284b17ea642332b2717a98a Mon Sep 17 00:00:00 2001 From: "Zhou (Link) Fang" <43075439+linkfang@users.noreply.github.com> Date: Thu, 26 Aug 2021 14:52:41 -0400 Subject: [PATCH 09/14] Added new logic and text for WG page (#270) * Added new logic and text * Added new logic to handle wg rep same as company one * Moved wg related func based on feedback * Fixed checkbox issue --- src/main/www/src/Utils/formFunctionHelpers.js | 46 ++- .../src/components/Application/Application.js | 9 + .../CompanyInformation/CompanyInformation.js | 81 ++++-- .../CompanyInformationContacts.js | 19 +- .../components/Application/Review/Review.tsx | 2 +- .../Application/WorkingGroups/WorkingGroup.js | 30 +- .../WorkingGroupEffectiveDate.js | 34 --- .../WorkingGroupParticipationLevel.js | 15 +- .../WorkingGroupRepresentative.js | 50 +++- .../WorkingGroups/WorkingGroupsWrapper.js | 274 ++++++++---------- .../FormComponents/formFieldModel.js | 3 +- 11 files changed, 287 insertions(+), 276 deletions(-) delete mode 100644 src/main/www/src/components/Application/WorkingGroups/WorkingGroupEffectiveDate.js diff --git a/src/main/www/src/Utils/formFunctionHelpers.js b/src/main/www/src/Utils/formFunctionHelpers.js index d958786c..50d20189 100644 --- a/src/main/www/src/Utils/formFunctionHelpers.js +++ b/src/main/www/src/Utils/formFunctionHelpers.js @@ -178,7 +178,8 @@ export function matchContactFields(existingContactData) { */ export function matchWorkingGroupFields( existingworkingGroupData, - workingGroupsOptions + workingGroupsOptions, + existingCompanyContact, ) { var res = []; // Array @@ -186,6 +187,12 @@ export function matchWorkingGroupFields( let wg = workingGroupsOptions?.find( (el) => el.label === item?.working_group_id ); + const basicRepInfo = { + firstName: item?.contact?.first_name || '', + lastName: item?.contact?.last_name || '', + jobtitle: item?.contact?.job_title || '', + email: item?.contact?.email || '', + }; res.push({ id: item?.id || '', workingGroup: @@ -197,11 +204,12 @@ export function matchWorkingGroupFields( participationLevel: item?.participation_level || '', effectiveDate: item?.effective_date?.substring(0, 10) || '', workingGroupRepresentative: { - firstName: item?.contact?.first_name || '', - lastName: item?.contact?.last_name || '', - jobtitle: item?.contact?.job_title || '', - email: item?.contact?.email || '', + ...basicRepInfo, id: item?.contact?.id || '', + sameAsCompany: checkSameContact( + existingCompanyContact, + basicRepInfo + ), }, }); }); @@ -305,9 +313,7 @@ export function matchWGFieldsToBackend(eachWorkingGroupData, formId) { formId ); - const theDate = eachWorkingGroupData?.effectiveDate - ? new Date(eachWorkingGroupData?.effectiveDate) - : new Date(); + const theDate = new Date(); return { id: eachWorkingGroupData?.id, @@ -371,7 +377,29 @@ export async function executeSendDataByStep(step, formData, formId, userId, setF method: setFieldValueObj.method, } ); - callSendData(formId, '', matchMembershipLevelFieldsToBackend(formData, formId, userId), ''); + callSendData( + formId, + '', + matchMembershipLevelFieldsToBackend(formData, formId, userId), + '' + ); + let isWGRepSameAsCompany = false; + formData.workingGroups.map( + (wg) => (isWGRepSameAsCompany = wg.workingGroupRepresentative?.sameAsCompany || isWGRepSameAsCompany) + ); + // only do this API call when there is at least 1 WG rep is same as company rep + if (isWGRepSameAsCompany) { + formData.workingGroups.forEach((item, index) => { + callSendData( + formId, + END_POINT.working_groups, + matchWGFieldsToBackend(item, formId), + '', + setFieldValueObj, + index + ); + }); + } break; case 2: diff --git a/src/main/www/src/components/Application/Application.js b/src/main/www/src/components/Application/Application.js index 0d2be384..695bfaf5 100644 --- a/src/main/www/src/components/Application/Application.js +++ b/src/main/www/src/components/Application/Application.js @@ -25,6 +25,8 @@ export default function Application() { const [isStartNewForm, setIsStartNewForm] = useState(true); const [isLoginExpired, setIsLoginExpired] = useState(false); const [isTermChecked, setIsTermChecked] = useState(false); + const [fullWorkingGroupList, setFullWorkingGroupList] = useState([]); + const [workingGroupsUserJoined, setWorkingGroupsUserJoined] = useState([]); const goToNextStep = (pageIndex, nextPage) => { if (furthestPage.index <= pageIndex) @@ -280,6 +282,10 @@ export default function Application() { ) : ( // if uses are not allowed to visit this page, @@ -303,7 +309,10 @@ export default function Application() { {furthestPage.index >= 3 ? ( ) : ( diff --git a/src/main/www/src/components/Application/CompanyInformation/CompanyInformation.js b/src/main/www/src/components/Application/CompanyInformation/CompanyInformation.js index c1bc4cb6..e66c04cc 100644 --- a/src/main/www/src/components/Application/CompanyInformation/CompanyInformation.js +++ b/src/main/www/src/components/Application/CompanyInformation/CompanyInformation.js @@ -21,6 +21,10 @@ import { import CustomStepButton from '../../UIComponents/Button/CustomStepButton'; import CompanyInformationVAT from './CompanyInformationVAT'; import { makeStyles } from '@material-ui/core'; +import { + fetchAvailableFullWorkingGroupList, + fetchWorkingGroupsUserJoined, +} from '../WorkingGroups/WorkingGroupsWrapper'; /** * Wrapper for Contacts and Company components @@ -35,6 +39,8 @@ import { makeStyles } from '@material-ui/core'; * - formField: the form field in formModels/formFieldModel.js */ +let hasWGData = false; + const useStyles = makeStyles(() => ({ textField: { marginBottom: 14, @@ -48,10 +54,19 @@ const useStyles = makeStyles(() => ({ let hasOrgData = false; let hasMembershipLevelData = false; -const CompanyInformation = ({ formik, isStartNewForm }) => { +const CompanyInformation = ({ + formik, + isStartNewForm, + formikWG, + fullWorkingGroupList, + setFullWorkingGroupList, + setWorkingGroupsUserJoined, +}) => { const { currentFormId } = useContext(MembershipContext); // current chosen form id const [loading, setLoading] = useState(true); const { setFieldValue } = formik; + const setWGFieldValue = formikWG.setFieldValue; + const companyRep = formik.values.representative.member; useEffect(() => { scrollToTop(); @@ -84,24 +99,12 @@ const CompanyInformation = ({ formik, isStartNewForm }) => { // Using promise pool, because in first step, // need to get company data, and contacts data let pool = [ - fetch( - url_prefix_local + - `/${currentFormId}/` + - END_POINT.organizations + - url_suffix_local, - { - headers: FETCH_HEADER, - } - ), - fetch( - url_prefix_local + - `/${currentFormId}/` + - END_POINT.contacts + - url_suffix_local, - { - headers: FETCH_HEADER, - } - ), + fetch(url_prefix_local + `/${currentFormId}/` + END_POINT.organizations + url_suffix_local, { + headers: FETCH_HEADER, + }), + fetch(url_prefix_local + `/${currentFormId}/` + END_POINT.contacts + url_suffix_local, { + headers: FETCH_HEADER, + }), ]; Promise.all(pool) .then((res) => @@ -140,10 +143,7 @@ const CompanyInformation = ({ formik, isStartNewForm }) => { // if nested, it will automatically map the properties and values setFieldValue('representative', tempContacts.organizationContacts); - setFieldValue( - 'signingAuthorityRepresentative', - tempContacts.signingAuthorityRepresentative - ); + setFieldValue('signingAuthorityRepresentative', tempContacts.signingAuthorityRepresentative); hasOrgData = true; } setLoading(false); @@ -202,6 +202,35 @@ const CompanyInformation = ({ formik, isStartNewForm }) => { } }, [isStartNewForm, setFieldValue, currentFormId]); + useEffect(() => { + fetchAvailableFullWorkingGroupList(setFullWorkingGroupList); + }, [setFullWorkingGroupList]); + + useEffect(() => { + if (!isStartNewForm && !hasWGData && fullWorkingGroupList.length > 0 && companyRep.firstName) { + // continue with an existing one and there is no working group data + fetchWorkingGroupsUserJoined( + currentFormId, + fullWorkingGroupList, + setWorkingGroupsUserJoined, + setWGFieldValue, + companyRep, + setLoading + ); + hasWGData = true; + } else { + setLoading(false); + } + }, [ + isStartNewForm, + currentFormId, + fullWorkingGroupList, + setFieldValue, + companyRep, + setWGFieldValue, + setWorkingGroupsUserJoined, + ]); + // If it is in loading status or hasn't gotten the form id, // only return a loading spinning if (loading || !currentFormId) { @@ -213,11 +242,11 @@ const CompanyInformation = ({ formik, isStartNewForm }) => {

    Company Information

    - Please complete your company information below. This should be the - legal name and address of your organization. + Please complete your company information below. This should be the legal name and address of your + organization.

    - +
    diff --git a/src/main/www/src/components/Application/CompanyInformation/CompanyInformationContacts.js b/src/main/www/src/components/Application/CompanyInformation/CompanyInformationContacts.js index a5915e35..fce21d24 100644 --- a/src/main/www/src/components/Application/CompanyInformation/CompanyInformationContacts.js +++ b/src/main/www/src/components/Application/CompanyInformation/CompanyInformationContacts.js @@ -17,7 +17,7 @@ import { Checkbox, FormControlLabel } from '@material-ui/core'; * * @returns */ -const Contacts = ({ formik }) => { +const Contacts = ({ formik, formikWG }) => { // the boolean form value of "is marketing Rep. the same as company Rep.?" const isMarketingSameAsCompany = formik.values.representative.marketing.sameAsCompany; @@ -88,6 +88,23 @@ const Contacts = ({ formik }) => { } formik.setFieldValue('representative', newRepresentativeValue); + + let isWGRepSameAsCompany = false; + const newWG = formikWG.values.workingGroups.map((wg) => { + isWGRepSameAsCompany = wg.workingGroupRepresentative?.sameAsCompany || isWGRepSameAsCompany; + return wg.workingGroupRepresentative?.sameAsCompany + ? { + ...wg, + workingGroupRepresentative: { + ...memberRepInfo, + id: wg.workingGroupRepresentative.id || '', + sameAsCompany: wg.workingGroupRepresentative.sameAsCompany, + }, + } + : wg; + }); + // only call setFieldValue when there is at least 1 wg rep has sameAsCompany: true + isWGRepSameAsCompany && formikWG.setFieldValue('workingGroups', newWG); }; const generateContacts = ( diff --git a/src/main/www/src/components/Application/Review/Review.tsx b/src/main/www/src/components/Application/Review/Review.tsx index 09e8a20f..2656644e 100644 --- a/src/main/www/src/components/Application/Review/Review.tsx +++ b/src/main/www/src/components/Application/Review/Review.tsx @@ -188,7 +188,7 @@ const Review: React.FC = ({ values, submitForm, isTermChecked, setI
-
{new Date(el.effectiveDate).toLocaleDateString()}
+
{new Date().toLocaleDateString()}
diff --git a/src/main/www/src/components/Application/WorkingGroups/WorkingGroup.js b/src/main/www/src/components/Application/WorkingGroups/WorkingGroup.js index edf604da..5ef29b68 100644 --- a/src/main/www/src/components/Application/WorkingGroups/WorkingGroup.js +++ b/src/main/www/src/components/Application/WorkingGroups/WorkingGroup.js @@ -1,7 +1,6 @@ import { useContext } from 'react'; import MembershipContext from '../../../Context/MembershipContext'; import WorkingGroupParticipationLevel from './WorkingGroupParticipationLevel'; -import WorkingGroupEffectiveDate from './WorkingGroupEffectiveDate'; import WorkingGroupsRepresentative from './WorkingGroupRepresentative'; import { deleteData } from '../../../Utils/formFunctionHelpers'; import { @@ -12,7 +11,7 @@ import { import Autocomplete from '@material-ui/lab/Autocomplete'; import { makeStyles, TextField } from '@material-ui/core'; import { FieldArray } from 'formik'; -import Loading from '../../UIComponents/Loading/Loading'; +import { initialValues } from '../../UIComponents/FormComponents/formFieldModel'; /** * Wrapper for Working Group Selector, @@ -27,19 +26,7 @@ import Loading from '../../UIComponents/Loading/Loading'; * - formField: the form field in formModels/formFieldModel.js */ -const each_workingGroupField = { - id: '', - workingGroup: '', - participationLevel: '', - effectiveDate: '', - workingGroupRepresentative: { - firstName: '', - lastName: '', - jobtitle: '', - email: '', - id: '', - }, -}; +const each_workingGroupField = initialValues.workingGroups[0]; const useStyles = makeStyles(() => ({ textField: { @@ -51,7 +38,7 @@ const useStyles = makeStyles(() => ({ }, })); -const WorkingGroup = ({ formik, fullWorkingGroupList, isLoading }) => { +const WorkingGroup = ({ formik, fullWorkingGroupList, formikOrgValue }) => { const classes = useStyles(); const { currentFormId } = useContext(MembershipContext); @@ -87,9 +74,7 @@ const WorkingGroup = ({ formik, fullWorkingGroupList, isLoading }) => { } }; - return isLoading ? ( - - ) : ( + return ( ( @@ -211,13 +196,8 @@ const WorkingGroup = ({ formik, fullWorkingGroupList, isLoading }) => { fullWorkingGroupList={fullWorkingGroupList} formik={formik} /> - { - const theIndex = index; - return ( - <> -

- What is the effective date for your Membership Agreement/ Working Group - Participation Agreement? - * -

-
-
- -
-
- - ); -}; - -export default EffectiveDate; diff --git a/src/main/www/src/components/Application/WorkingGroups/WorkingGroupParticipationLevel.js b/src/main/www/src/components/Application/WorkingGroups/WorkingGroupParticipationLevel.js index abdcdf4a..c8dc11dd 100644 --- a/src/main/www/src/components/Application/WorkingGroups/WorkingGroupParticipationLevel.js +++ b/src/main/www/src/components/Application/WorkingGroups/WorkingGroupParticipationLevel.js @@ -13,8 +13,8 @@ import DropdownMenu from '../../UIComponents/Inputs/DropdownMenu'; const ParticipationLevel = ({ name, workingGroupUserJoined, fullWorkingGroupList, formik, index }) => { const [participationLevelOptions, setParticipationLevelOptions] = useState([]); const [selectedWG, setSelectedWG] = useState(); - const theIndex = index; + useEffect(() => { // If have selected working group, find this working group's // participation levels, and pass to the react-select option @@ -56,11 +56,16 @@ const ParticipationLevel = ({ name, workingGroupUserJoined, fullWorkingGroupList

- You can find additional information about {selectedWG?.label} in the{' '} + Each Working Group has different participation levels and restrictions on who can join at those levels (e.g., + Guest Member level is typically restricted to non-profit organizations). See the{' '} - {selectedWG?.label} charter - - . + charter + {' '} + for full details on which choice is best for you, and to see the working group fees associated with joining this + working group. Note: working group fees are in addition to the membership fees associated with joining the + Eclipse Foundation. Please{' '} + contact our membership team with any + questions.

); diff --git a/src/main/www/src/components/Application/WorkingGroups/WorkingGroupRepresentative.js b/src/main/www/src/components/Application/WorkingGroups/WorkingGroupRepresentative.js index 91721787..51ac5d51 100644 --- a/src/main/www/src/components/Application/WorkingGroups/WorkingGroupRepresentative.js +++ b/src/main/www/src/components/Application/WorkingGroups/WorkingGroupRepresentative.js @@ -1,5 +1,6 @@ import Input from '../../UIComponents/Inputs/Input'; import { formField } from '../../UIComponents/FormComponents/formFieldModel'; +import { Checkbox, FormControlLabel } from '@material-ui/core'; /** * Render Working Group Representative input component @@ -9,15 +10,40 @@ import { formField } from '../../UIComponents/FormComponents/formFieldModel'; * * - formField: the form field in formModels/formFieldModel.js */ -const WorkingGroupRepresentative = ({ name, index, formik }) => { +const WorkingGroupRepresentative = ({ name, index, formik, formikOrgValue }) => { const { workingGroupRepresentative } = formField; const theIndex = index; + + const handleCheckboxChange = (isChecked) => { + const repInfo = isChecked + ? formikOrgValue.representative.member + : formik.values.workingGroups[theIndex].workingGroupRepresentative; + + const newValues = { + ...repInfo, + sameAsCompany: isChecked, + id: formik.values.workingGroups[theIndex].workingGroupRepresentative.id, + }; + formik.setFieldValue(`workingGroups[${theIndex}].workingGroupRepresentative`, newValues); + }; + return ( <>

- Who is the working group representative? + Who is to serve as your organization’s Member Representative with the Working Group? *

+ handleCheckboxChange(ev.target.checked, 'marketing')} + /> + } + label="Same as Member Representative" + />
{workingGroupRepresentative.map((el) => (
@@ -28,23 +54,15 @@ const WorkingGroupRepresentative = ({ name, index, formik }) => { ariaLabel={`${name} ${name}.${el.name}`} onChange={formik.handleChange} requiredMark={true} - value={ - formik.values.workingGroups[theIndex] - .workingGroupRepresentative[`${el.name}`] - } + disableInput={formik.values.workingGroups[theIndex].workingGroupRepresentative.sameAsCompany} + value={formik.values.workingGroups[theIndex].workingGroupRepresentative[`${el.name}`]} error={ - formik.touched.workingGroups?.[theIndex] - ?.workingGroupRepresentative?.[`${el.name}`] && - Boolean( - formik.errors.workingGroups?.[theIndex] - ?.workingGroupRepresentative?.[`${el.name}`] - ) + formik.touched.workingGroups?.[theIndex]?.workingGroupRepresentative?.[`${el.name}`] && + Boolean(formik.errors.workingGroups?.[theIndex]?.workingGroupRepresentative?.[`${el.name}`]) } helperText={ - formik.touched.workingGroups?.[theIndex] - ?.workingGroupRepresentative?.[`${el.name}`] && - formik.errors.workingGroups?.[theIndex] - ?.workingGroupRepresentative?.[`${el.name}`] + formik.touched.workingGroups?.[theIndex]?.workingGroupRepresentative?.[`${el.name}`] && + formik.errors.workingGroups?.[theIndex]?.workingGroupRepresentative?.[`${el.name}`] } />
diff --git a/src/main/www/src/components/Application/WorkingGroups/WorkingGroupsWrapper.js b/src/main/www/src/components/Application/WorkingGroups/WorkingGroupsWrapper.js index d5ba5a6e..0d52be14 100644 --- a/src/main/www/src/components/Application/WorkingGroups/WorkingGroupsWrapper.js +++ b/src/main/www/src/components/Application/WorkingGroups/WorkingGroupsWrapper.js @@ -7,7 +7,6 @@ import { requestErrorHandler, scrollToTop, } from '../../../Utils/formFunctionHelpers'; -import Loading from '../../UIComponents/Loading/Loading'; import { END_POINT, API_PREFIX_FORM, @@ -48,24 +47,16 @@ import { initialValues } from '../../UIComponents/FormComponents/formFieldModel' * - formField: the form field in formModels/formFieldModel.js */ -let hasWGData = false; - -const WorkingGroupsWrapper = ({ formik, isStartNewForm }) => { +const WorkingGroupsWrapper = ({ formik, formikOrgValue, fullWorkingGroupList, workingGroupsUserJoined }) => { const { currentFormId } = useContext(MembershipContext); - const { setFieldValue } = formik; - const [isLoading, setIsLoading] = useState(true); - const [workingGroupsUserJoined, setWorkingGroupsUserJoined] = useState([]); - const [fullWorkingGroupList, setFullWorkingGroupList] = useState([]); const [shouldOpen, setShouldOpen] = useState(false); - const handleIsJoiningWG = () => { - const isJoiningWG = formik.values.isJoiningWG; - - if (isJoiningWG) { - setShouldOpen(true); + const handleSkipJoiningWG = () => { + const skipJoiningWG = formik.values.skipJoiningWG; + if (skipJoiningWG) { + formik.setFieldValue('skipJoiningWG', !skipJoiningWG); } else { - formik.setFieldValue('isJoiningWG', !isJoiningWG); - formik.setFieldValue('workingGroups', initialValues.workingGroups); + setShouldOpen(true); } }; @@ -74,17 +65,13 @@ const WorkingGroupsWrapper = ({ formik, isStartNewForm }) => { }; const handleClearData = () => { - // if user uncheck it, then we need to reset WG form + // if user check it, we need to delete all wgs in formik and db formik.values.workingGroups.map((item) => { - deleteData( - currentFormId, - END_POINT.working_groups, - item.id, - formik.resetForm, - '' - ); + deleteData(currentFormId, END_POINT.working_groups, item.id, console.log, `Deleted ${item.workingGroup.label}`); return null; }); + formik.setFieldValue('skipJoiningWG', true); + formik.setFieldValue('workingGroups', initialValues.workingGroups); closeModal(); }; @@ -92,137 +79,20 @@ const WorkingGroupsWrapper = ({ formik, isStartNewForm }) => { scrollToTop(); }, []); - // Fetch data only once and prefill data, as long as - // fetchWorkingGroupsData Function does not change, - // will not cause re-render again - useEffect(() => { - // Fetch the full availabe working group list that user can join - const fetchAvailableFullWorkingGroupList = () => { - let url_prefix_local; - if (getCurrentMode() === MODE_REACT_ONLY) { - url_prefix_local = 'membership_data'; - setFullWorkingGroupList(FULL_WORKING_GROUP_LIST_FOR_REACT_ONLY); - return; - } - - if (getCurrentMode() === MODE_REACT_API) { - url_prefix_local = api_prefix() + '/'; - } - - fetch(url_prefix_local + END_POINT.working_groups, { - headers: FETCH_HEADER, - }) - .then((res) => { - if (res.ok) return res.json(); - - requestErrorHandler(res.status); - throw res.status; - }) - .then((data) => { - let options = data.map((item) => ({ - label: item.title, - value: item.title, - participation_levels: item.levels, - charter: item.resources.charter - })); - setFullWorkingGroupList(options); - }) - .catch((err) => { - requestErrorHandler(err); - console.log(err); - }); - }; - - fetchAvailableFullWorkingGroupList(); - }, []); - - useEffect(() => { - // Fetch the working groups user has joined - const fetchWorkingGroupsUserJoined = () => { - // All pre-process: if running without server, - // use fake json data; if running with API, use API - - let url_prefix_local; - let url_suffix_local = ''; - if (getCurrentMode() === MODE_REACT_ONLY) { - url_prefix_local = 'membership_data'; - url_suffix_local = '.json'; - } - - if (getCurrentMode() === MODE_REACT_API) { - url_prefix_local = API_PREFIX_FORM; - } - - fetch( - url_prefix_local + - `/${currentFormId}/` + - END_POINT.working_groups + - url_suffix_local, - { - headers: FETCH_HEADER, - } - ) - .then((res) => { - if (res.ok) return res.json(); - - requestErrorHandler(res.status); - throw res.status; - }) - .then((data) => { - if (data.length) { - // matchWorkingGroupFields(): Call the the function to map - // the retrived working groups backend data to fit frontend, and - // setFieldValue(): Prefill Data --> Call the setFieldValue - // of Formik, to set workingGroups field with the mapped data - const theGroupsUserJoined = matchWorkingGroupFields( - data, - fullWorkingGroupList - ); - setWorkingGroupsUserJoined(theGroupsUserJoined); - setFieldValue('isJoiningWG', true); - setFieldValue('workingGroups', theGroupsUserJoined); - hasWGData = true; - } - setIsLoading(false); - }) - .catch((err) => { - requestErrorHandler(err); - console.log(err); - }); - }; - - if (!isStartNewForm && !hasWGData && fullWorkingGroupList.length > 0) { - // continue with an existing one and there is no working group data - fetchWorkingGroupsUserJoined(); - } else { - setIsLoading(false); - } - }, [isStartNewForm, currentFormId, fullWorkingGroupList, setFieldValue]); - - if (isLoading) { - return ; - } - return (
-
+
- - {'Uncheck Joining a Working Group'} - + {'Skip Joining a Working Group'} - This will clear all saved data in this step. Proceed to - uncheck? + This will clear all saved data in this step. Proceed to uncheck? @@ -234,41 +104,129 @@ const WorkingGroupsWrapper = ({ formik, isStartNewForm }) => {

Working Group

+

+ Eclipse Foundation hosts a number of industry collaboration initiatives called Working Groups. While not + required, most Member organizations participate in one or more working groups. See a full list of Eclipse + Foundation working groups. +

+

+ Please complete the following details for joining a Working Group or you can skip joining a Working Group. +

handleIsJoiningWG()} + checked={formik.values.skipJoiningWG} + onChange={() => handleSkipJoiningWG()} /> } - label="Joining a Working Group" + label="Skip joining a Working Group" /> - {formik.values.isJoiningWG && ( + {!formik.values.skipJoiningWG && ( <> -

- Please complete the following details for joining a Working - Group -

+

Please complete the following details for joining a Working Group

)}
- + ); }; export default WorkingGroupsWrapper; + +// Fetch the working groups user has joined +export const fetchWorkingGroupsUserJoined = ( + currentFormId, + fullWorkingGroupList, + setWorkingGroupsUserJoined, + setWGFieldValue, + companyRep, + setLoading +) => { + // All pre-process: if running without server, + // use fake json data; if running with API, use API + + let url_prefix_local; + let url_suffix_local = ''; + if (getCurrentMode() === MODE_REACT_ONLY) { + url_prefix_local = 'membership_data'; + url_suffix_local = '.json'; + } + + if (getCurrentMode() === MODE_REACT_API) { + url_prefix_local = API_PREFIX_FORM; + } + + fetch(url_prefix_local + `/${currentFormId}/` + END_POINT.working_groups + url_suffix_local, { + headers: FETCH_HEADER, + }) + .then((res) => { + if (res.ok) return res.json(); + + requestErrorHandler(res.status); + throw res.status; + }) + .then((data) => { + if (data.length) { + // matchWorkingGroupFields(): Call the the function to map + // the retrived working groups backend data to fit frontend, and + // setFieldValue(): Prefill Data --> Call the setFieldValue + // of Formik, to set workingGroups field with the mapped data + const theGroupsUserJoined = matchWorkingGroupFields(data, fullWorkingGroupList, companyRep); + setWorkingGroupsUserJoined(theGroupsUserJoined); + setWGFieldValue('workingGroups', theGroupsUserJoined); + } + setLoading(false); + }) + .catch((err) => { + requestErrorHandler(err); + console.log(err); + }); +}; + +// Fetch the full availabe working group list that user can join +export const fetchAvailableFullWorkingGroupList = (setFullWorkingGroupList) => { + let url_prefix_local; + if (getCurrentMode() === MODE_REACT_ONLY) { + url_prefix_local = 'membership_data'; + setFullWorkingGroupList(FULL_WORKING_GROUP_LIST_FOR_REACT_ONLY); + return; + } + + if (getCurrentMode() === MODE_REACT_API) { + url_prefix_local = api_prefix() + '/'; + } + + fetch(url_prefix_local + END_POINT.working_groups, { + headers: FETCH_HEADER, + }) + .then((res) => { + if (res.ok) return res.json(); + + requestErrorHandler(res.status); + throw res.status; + }) + .then((data) => { + let options = data.map((item) => ({ + label: item.title, + value: item.title, + participation_levels: item.levels, + charter: item.resources.charter, + })); + setFullWorkingGroupList(options); + }) + .catch((err) => { + requestErrorHandler(err); + console.log(err); + }); +}; diff --git a/src/main/www/src/components/UIComponents/FormComponents/formFieldModel.js b/src/main/www/src/components/UIComponents/FormComponents/formFieldModel.js index c6761f8b..cb3b0fa3 100644 --- a/src/main/www/src/components/UIComponents/FormComponents/formFieldModel.js +++ b/src/main/www/src/components/UIComponents/FormComponents/formFieldModel.js @@ -95,11 +95,12 @@ export const initialValues = { jobtitle: '', email: '', id: '', + sameAsCompany: false, }, }, ], - isJoiningWG: false, + skipJoiningWG: false, signingAuthorityRepresentative: { firstName: '', -- GitLab From 5eb1686126e22c1822d4522b2eef5044afb421d6 Mon Sep 17 00:00:00 2001 From: "Zhou (Link) Fang" <43075439+linkfang@users.noreply.github.com> Date: Thu, 26 Aug 2021 15:45:21 -0400 Subject: [PATCH 10/14] Minor typos and formatting issues (#293) * Fixed typos * Fixed org type display issue --- .../components/Application/Review/Review.tsx | 22 +++++++++++-------- .../FormComponents/formFieldModel.js | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/main/www/src/components/Application/Review/Review.tsx b/src/main/www/src/components/Application/Review/Review.tsx index 2656644e..baa62310 100644 --- a/src/main/www/src/components/Application/Review/Review.tsx +++ b/src/main/www/src/components/Application/Review/Review.tsx @@ -3,6 +3,7 @@ import CustomStepButton from '../../UIComponents/Button/CustomStepButton'; import { FormValue } from '../../../Interfaces/form_interface'; import { scrollToTop } from '../../../Utils/formFunctionHelpers'; import { FormControlLabel, Checkbox } from '@material-ui/core'; +import { OPTIONS_FOR_ORG_TYPE } from '../../../Constants/Constants'; interface ReviewProps { values: FormValue; @@ -39,24 +40,27 @@ const Review: React.FC = ({ values, submitForm, isTermChecked, setI

Company Information

-
{values.organization.legalName}
+ +
{values.organization.legalName}
-
+
-
{values.organization.type}
-
-
- -
{values.organization.twitterHandle}
+
+ {OPTIONS_FOR_ORG_TYPE.find((item) => item.value === values.organization.type)?.label} +
-
+
+ +
{values.organization.twitterHandle}
+
+
{values.organization.revenue}
-
+
{values.organization.employeeCount}
diff --git a/src/main/www/src/components/UIComponents/FormComponents/formFieldModel.js b/src/main/www/src/components/UIComponents/FormComponents/formFieldModel.js index cb3b0fa3..2b41bd35 100644 --- a/src/main/www/src/components/UIComponents/FormComponents/formFieldModel.js +++ b/src/main/www/src/components/UIComponents/FormComponents/formFieldModel.js @@ -11,7 +11,7 @@ const provinceOrState = 'Province Or State'; const postalCode = 'Postal Code'; const country = 'Country'; const jobtitle = 'Job Title'; -const purchasingProcess = 'Require or Not'; +const purchasingProcess = 'Purchasing Process'; const vatNumber = 'VAT Number'; const countryOfRegistration = 'Country of Registration'; const REVENUE = 'Revenue'; -- GitLab From eaabc56795761cf36fb88ad0d944963b04dcbe37 Mon Sep 17 00:00:00 2001 From: "Zhou (Link) Fang" <43075439+linkfang@users.noreply.github.com> Date: Thu, 26 Aug 2021 15:56:59 -0400 Subject: [PATCH 11/14] Added more validation to match back-end ones (#292) * Added more validation * improved country validation * corrected the max length value to 255 * Added more validation * improved country validation * corrected the max length value to 255 * Improved return logic based on feedback --- src/main/www/src/Constants/Constants.js | 1 + .../CompanyInformationCompany.js | 30 ++++++-- .../CompanyInformationContacts.js | 16 ++--- .../CompanyInformationVAT.js | 25 ++++--- .../MembershipLevel/MembershipLevel.js | 2 + .../Application/WorkingGroups/WorkingGroup.js | 29 +++----- .../WorkingGroupParticipationLevel.js | 5 ++ .../FormComponents/ValidationSchema.js | 72 ++++++++++--------- .../FormComponents/formFieldModel.js | 2 +- .../UIComponents/Inputs/DropdownMenu.js | 7 +- .../components/UIComponents/Inputs/Input.js | 3 +- 11 files changed, 111 insertions(+), 81 deletions(-) diff --git a/src/main/www/src/Constants/Constants.js b/src/main/www/src/Constants/Constants.js index 59dd315a..205cafd8 100644 --- a/src/main/www/src/Constants/Constants.js +++ b/src/main/www/src/Constants/Constants.js @@ -31,6 +31,7 @@ export const REVIEW = 'Review'; export const HAS_TOKEN_EXPIRED = 'HAS_TOKEN_EXPIRED'; export const LOGIN_EXPIRED_MSG = 'Your session has expired, please sign in again.'; +export const MAX_LENGTH_HELPER_TEXT = 'The value exceeds max length 255 characters' export const PATH_NAME_ARRAY = [ '/company-info', diff --git a/src/main/www/src/components/Application/CompanyInformation/CompanyInformationCompany.js b/src/main/www/src/components/Application/CompanyInformation/CompanyInformationCompany.js index 1d305028..1c4743cc 100644 --- a/src/main/www/src/components/Application/CompanyInformation/CompanyInformationCompany.js +++ b/src/main/www/src/components/Application/CompanyInformation/CompanyInformationCompany.js @@ -3,7 +3,12 @@ import { formField } from '../../UIComponents/FormComponents/formFieldModel'; import Autocomplete from '@material-ui/lab/Autocomplete'; import { TextField } from '@material-ui/core'; import DropdownMenu from '../../UIComponents/Inputs/DropdownMenu'; -import { OPTIONS_FOR_ORG_TYPE, OPTIONS_FOR_REVENUE, OPTIONS_FOR_EMPLOYEE_COUNT, HELPERTEXT_FOR_REVENUE } from '../../../Constants/Constants'; +import { + OPTIONS_FOR_ORG_TYPE, + OPTIONS_FOR_REVENUE, + OPTIONS_FOR_EMPLOYEE_COUNT, + HELPERTEXT_FOR_REVENUE, +} from '../../../Constants/Constants'; /** * Render Oraganization selector (used React-Select) @@ -43,6 +48,8 @@ const CompanyInformationCompany = ({ formik, useStyles }) => { requiredMark={true} value={formik.values.organization.legalName} onChange={formik.handleChange} + error={formik.touched.organization?.legalName && Boolean(formik.errors.organization?.legalName)} + helperText={formik.errors.organization?.legalName} />
@@ -54,6 +61,8 @@ const CompanyInformationCompany = ({ formik, useStyles }) => { inputValue={formik.values.organization.type} optionsArray={OPTIONS_FOR_ORG_TYPE} handleChange={formik.handleChange} + error={formik.touched.organization?.type && Boolean(formik.errors.organization?.type)} + helperText={formik.errors.organization?.type} />
@@ -89,8 +98,10 @@ const CompanyInformationCompany = ({ formik, useStyles }) => { inputName={organizationRevenue.revenue.name} inputValue={formik.values.organization.revenue} optionsArray={OPTIONS_FOR_REVENUE} - helperText={HELPERTEXT_FOR_REVENUE} + explanationHelperText={HELPERTEXT_FOR_REVENUE} handleChange={(ev) => handleFieldChange(ev.target.value, 'organization.revenue')} + error={formik.touched.organization?.revenue && Boolean(formik.errors.organization?.revenue)} + helperText={formik.errors.organization?.revenue} />
@@ -100,6 +111,8 @@ const CompanyInformationCompany = ({ formik, useStyles }) => { inputValue={formik.values.organization.employeeCount} optionsArray={OPTIONS_FOR_EMPLOYEE_COUNT} handleChange={(ev) => handleFieldChange(ev.target.value, 'organization.employeeCount')} + error={formik.touched.organization?.employeeCount && Boolean(formik.errors.organization?.employeeCount)} + helperText={formik.errors.organization?.employeeCount} />
@@ -117,6 +130,8 @@ const CompanyInformationCompany = ({ formik, useStyles }) => { value={formik.values.organization.address.street} onChange={formik.handleChange} ariaLabel={`${organizationName.name}-address`} + error={formik.touched.organization?.address?.street && Boolean(formik.errors.organization?.address?.street)} + helperText={formik.errors.organization?.address?.street} />
@@ -128,6 +143,8 @@ const CompanyInformationCompany = ({ formik, useStyles }) => { value={formik.values.organization.address.city} onChange={formik.handleChange} ariaLabel={`${organizationName.name}-address`} + error={formik.touched.organization?.address?.city && Boolean(formik.errors.organization?.address?.city)} + helperText={formik.errors.organization?.address?.city} />
@@ -167,8 +184,9 @@ const CompanyInformationCompany = ({ formik, useStyles }) => { size="small" required={true} className={classes.textField} - error={Boolean(formik.errors.organization?.address?.country)} - helperText={formik.errors.organization?.address?.country} + error={formik.touched.organization?.address?.city && Boolean(formik.errors.organization?.address?.country)} + helperText={formik.touched.organization?.address?.city && formik.errors.organization?.address?.country} + oncha /> ); }} @@ -184,6 +202,8 @@ const CompanyInformationCompany = ({ formik, useStyles }) => { value={formik.values.organization.address.provinceOrState} onChange={formik.handleChange} ariaLabel={`${organizationName.name}-address`} + error={Boolean(formik.errors.organization?.address?.provinceOrState)} + helperText={formik.errors.organization?.address?.provinceOrState} />
@@ -196,6 +216,8 @@ const CompanyInformationCompany = ({ formik, useStyles }) => { value={formik.values.organization.address.postalCode} onChange={formik.handleChange} ariaLabel={`${organizationName.name}-address`} + error={Boolean(formik.errors.organization?.address?.postalCode)} + helperText={formik.errors.organization?.address?.postalCode} />
diff --git a/src/main/www/src/components/Application/CompanyInformation/CompanyInformationContacts.js b/src/main/www/src/components/Application/CompanyInformation/CompanyInformationContacts.js index fce21d24..79c20407 100644 --- a/src/main/www/src/components/Application/CompanyInformation/CompanyInformationContacts.js +++ b/src/main/www/src/components/Application/CompanyInformation/CompanyInformationContacts.js @@ -107,12 +107,7 @@ const Contacts = ({ formik, formikWG }) => { isWGRepSameAsCompany && formikWG.setFieldValue('workingGroups', newWG); }; - const generateContacts = ( - representativeFields, - prefix, - type, - disableInput - ) => ( + const generateContacts = (representativeFields, prefix, type, disableInput) => ( <> {representativeFields.map((el, index) => (
@@ -124,12 +119,13 @@ const Contacts = ({ formik, formikWG }) => { requiredMark={true} disableInput={disableInput} onChange={ - type === 'member' - ? (ev) => handleMemberInputChange(ev.target.value, el.name) - : formik.handleChange + type === 'member' ? (ev) => handleMemberInputChange(ev.target.value, el.name) : formik.handleChange } value={formik.values.representative?.[type]?.[el.name]} - error={Boolean(formik.errors.representative?.[type]?.[el.name])} + error={ + formik.touched.representative?.[type]?.[el.name] && + Boolean(formik.errors.representative?.[type]?.[el.name]) + } helperText={formik.errors.representative?.[type]?.[el.name]} />
diff --git a/src/main/www/src/components/Application/CompanyInformation/CompanyInformationVAT.js b/src/main/www/src/components/Application/CompanyInformation/CompanyInformationVAT.js index 90df1818..08a7aac9 100644 --- a/src/main/www/src/components/Application/CompanyInformation/CompanyInformationVAT.js +++ b/src/main/www/src/components/Application/CompanyInformation/CompanyInformationVAT.js @@ -23,17 +23,11 @@ export default function CompanyInformationVAT({ formik }) { return ( <> -

+

Purchasing Process *

-

- Does your organization require a Purchase Order to facilitate payment of - your membership dues? -

+

Does your organization require a Purchase Order to facilitate payment of your membership dues?

@@ -72,6 +71,11 @@ export default function CompanyInformationVAT({ formik }) { value={formik.values.purchasingAndVAT.vatNumber} onChange={formik.handleChange} ariaLabel={`vatRegistration`} + error={ + formik.touched.purchasingAndVAT?.vatNumber && + Boolean(formik.errors.purchasingAndVAT?.vatNumber) + } + helperText={formik.errors.purchasingAndVAT?.vatNumber} />
@@ -84,6 +88,11 @@ export default function CompanyInformationVAT({ formik }) { value={formik.values.purchasingAndVAT.countryOfRegistration} onChange={formik.handleChange} ariaLabel={`vatRegistration`} + error={ + formik.touched.purchasingAndVAT?.countryOfRegistration && + Boolean(formik.errors.purchasingAndVAT?.countryOfRegistration) + } + helperText={formik.errors.purchasingAndVAT?.countryOfRegistration} />
diff --git a/src/main/www/src/components/Application/MembershipLevel/MembershipLevel.js b/src/main/www/src/components/Application/MembershipLevel/MembershipLevel.js index 3627a34b..9188e576 100644 --- a/src/main/www/src/components/Application/MembershipLevel/MembershipLevel.js +++ b/src/main/www/src/components/Application/MembershipLevel/MembershipLevel.js @@ -41,6 +41,8 @@ const MembershipLevel = ({ formik }) => { inputValue={formik.values.membershipLevel} optionsArray={MEMBERSHIP_LEVELS} handleChange={formik.handleChange} + error={formik.touched.membershipLevel && Boolean(formik.errors.membershipLevel)} + helperText={formik.errors.membershipLevel} />
diff --git a/src/main/www/src/components/Application/WorkingGroups/WorkingGroup.js b/src/main/www/src/components/Application/WorkingGroups/WorkingGroup.js index 5ef29b68..9c4fe160 100644 --- a/src/main/www/src/components/Application/WorkingGroups/WorkingGroup.js +++ b/src/main/www/src/components/Application/WorkingGroups/WorkingGroup.js @@ -143,30 +143,17 @@ const WorkingGroup = ({ formik, fullWorkingGroupList, formikOrgValue }) => { const wgLabelPropery = `${workingGroupsLabel}.${index}.workingGroup-label`; // if array.find returns a wg obejct, then it means it's already selected - const selectedWGValue = - formik.values.workingGroups.find((item) => { - if ( - item.workingGroup?.label === inputValue && - item['workingGroup-label'] === inputValue - ) { - return true; - } else { - return false; - } - }); + const selectedWGValue = formik.values.workingGroups.find( + (item) => + item.workingGroup?.label === inputValue && item['workingGroup-label'] === inputValue + ); // if the wg user types is already selected somewhere else, // then make the validation fail and show error message if (selectedWGValue) { - formik.setFieldValue( - wgLabelPropery, - `${inputValue} already selected` - ); + formik.setFieldValue(wgLabelPropery, `${inputValue} already selected`); } else { - formik.setFieldValue( - wgLabelPropery, - inputValue || null - ); + formik.setFieldValue(wgLabelPropery, inputValue || null); } }} label={WORKING_GROUPS} @@ -176,9 +163,11 @@ const WorkingGroup = ({ formik, fullWorkingGroupList, formikOrgValue }) => { required={true} className={classes.textField} error={Boolean( - formik.errors.workingGroups?.[index]?.['workingGroup'] + formik.touched.workingGroups?.[index]?.['workingGroup'] && + formik.errors.workingGroups?.[index]?.['workingGroup'] )} helperText={ + formik.touched.workingGroups?.[index]?.['workingGroup'] && formik.errors.workingGroups?.[index]?.['workingGroup'] } /> diff --git a/src/main/www/src/components/Application/WorkingGroups/WorkingGroupParticipationLevel.js b/src/main/www/src/components/Application/WorkingGroups/WorkingGroupParticipationLevel.js index c8dc11dd..99583052 100644 --- a/src/main/www/src/components/Application/WorkingGroups/WorkingGroupParticipationLevel.js +++ b/src/main/www/src/components/Application/WorkingGroups/WorkingGroupParticipationLevel.js @@ -51,6 +51,11 @@ const ParticipationLevel = ({ name, workingGroupUserJoined, fullWorkingGroupList inputValue={formik.values.workingGroups[theIndex]['participationLevel']} optionsArray={participationLevelOptions} handleChange={formik.handleChange} + error={ + formik.touched.workingGroups?.[theIndex]?.['participationLevel'] && + Boolean(formik.errors.workingGroups?.[theIndex]?.['participationLevel']) + } + helperText={formik.errors.workingGroups?.[theIndex]?.['participationLevel']} /> )}
diff --git a/src/main/www/src/components/UIComponents/FormComponents/ValidationSchema.js b/src/main/www/src/components/UIComponents/FormComponents/ValidationSchema.js index 3a8406c9..a9608258 100644 --- a/src/main/www/src/components/UIComponents/FormComponents/ValidationSchema.js +++ b/src/main/www/src/components/UIComponents/FormComponents/ValidationSchema.js @@ -1,4 +1,5 @@ import * as yup from 'yup'; +import { MAX_LENGTH_HELPER_TEXT } from '../../../Constants/Constants'; import { requiredErrorMsg } from './formFieldModel'; /** @@ -35,6 +36,15 @@ const countryList = require('country-list') .getNames() .map((item) => item); +const REQUIRED_MAX_YUP = yup.string().required(requiredErrorMsg).max(255, MAX_LENGTH_HELPER_TEXT); +const MAX_YUP = yup.string().max(255, MAX_LENGTH_HELPER_TEXT); +const CONTACT_YUP = yup.object().shape({ + email: yup.string().required(requiredErrorMsg).email('Please enter a valid email'), + firstName: REQUIRED_MAX_YUP, + lastName: REQUIRED_MAX_YUP, + jobtitle: REQUIRED_MAX_YUP, +}); + export const validationSchema = [ // First step - company Info yup.object().shape({ @@ -43,9 +53,17 @@ export const validationSchema = [ address: yup.object().shape({ country: yup .mixed() + .required('Please enter/select a valid country name') .oneOf(countryList, 'Please enter/select a valid country name'), + street: REQUIRED_MAX_YUP, + provinceOrState: MAX_YUP, + postalCode: MAX_YUP, + city: REQUIRED_MAX_YUP, }), - + legalName: REQUIRED_MAX_YUP, + revenue: REQUIRED_MAX_YUP, + employeeCount: REQUIRED_MAX_YUP, + type: REQUIRED_MAX_YUP, twitterHandle: yup .string() .min(2, 'Twitter handle is too short') @@ -53,21 +71,20 @@ export const validationSchema = [ .matches(/^@([A-Za-z0-9_])*$/, 'Please enter a valid Twitter handle'), }), representative: yup.object().shape({ - member: yup.object().shape({ - email: yup.string().email('Please enter a valid email'), - }), - marketing: yup.object().shape({ - email: yup.string().email('Please enter a valid email'), - }), - accounting: yup.object().shape({ - email: yup.string().email('Please enter a valid email'), - }), + member: CONTACT_YUP, + marketing: CONTACT_YUP, + accounting: CONTACT_YUP, + }), + purchasingAndVAT: yup.object().shape({ + purchasingProcess: REQUIRED_MAX_YUP, + vatNumber: MAX_YUP, + countryOfRegistration: MAX_YUP, }), }), // Second step - membership level yup.object().shape({ - 'membershipLevel-label': yup.mixed(), + membershipLevel: REQUIRED_MAX_YUP, }), // Third step - working groups @@ -77,34 +94,21 @@ export const validationSchema = [ workingGroup: yup .object() .nullable() - .test( - 'workingGroup', - 'Please enter/select a valid working group', - function (selectedWG) { - const allWorkingGroups = this.options.parent?.allWorkingGroups; - const typedWG = this.options.parent?.['workingGroup-label']; - const isValid = - allWorkingGroups?.includes(typedWG) && selectedWG?.label - ? true - : false; - - return typedWG ? isValid : true; - } - ), - workingGroupRepresentative: yup.object().shape({ - email: yup.string().email('Please enter a valid email'), - }), + .required('Please enter/select a valid working group') + .test('workingGroup', 'Please enter/select a valid working group', function (selectedWG) { + const allWorkingGroups = this.options.parent?.allWorkingGroups; + const typedWG = this.options.parent?.['workingGroup-label']; + const isValid = allWorkingGroups?.includes(typedWG) && selectedWG?.label ? true : false; + return typedWG ? isValid : true; + }), + participationLevel: REQUIRED_MAX_YUP, + workingGroupRepresentative: CONTACT_YUP, }) ), }), // Forth, signing Authority yup.object().shape({ - signingAuthorityRepresentative: yup.object().shape({ - firstName: yup.string().required(`${requiredErrorMsg}`), - lastName: yup.string().required(`${requiredErrorMsg}`), - jobtitle: yup.string().required(`${requiredErrorMsg}`), - email: yup.string().email('Please enter a valid email'), - }), + signingAuthorityRepresentative: CONTACT_YUP, }), ]; diff --git a/src/main/www/src/components/UIComponents/FormComponents/formFieldModel.js b/src/main/www/src/components/UIComponents/FormComponents/formFieldModel.js index 2b41bd35..8d215ba6 100644 --- a/src/main/www/src/components/UIComponents/FormComponents/formFieldModel.js +++ b/src/main/www/src/components/UIComponents/FormComponents/formFieldModel.js @@ -18,7 +18,7 @@ const REVENUE = 'Revenue'; const EMPLOYEE_COUNT = 'Employee Count'; const ORG_TYPE = 'Organization Type'; -export const requiredErrorMsg = 'is required'; +export const requiredErrorMsg = 'Required field'; // Initial values passed to Formik, this defines // the form fields, names, and nesting relations of the whole form diff --git a/src/main/www/src/components/UIComponents/Inputs/DropdownMenu.js b/src/main/www/src/components/UIComponents/Inputs/DropdownMenu.js index 083b7bbc..ae52d812 100644 --- a/src/main/www/src/components/UIComponents/Inputs/DropdownMenu.js +++ b/src/main/www/src/components/UIComponents/Inputs/DropdownMenu.js @@ -14,11 +14,11 @@ const useStyles = makeStyles(() => ({ }, })); -export default function DropdownMenu({ inputLabel, inputName, inputValue, optionsArray, handleChange, helperText }) { +export default function DropdownMenu({ inputLabel, inputName, inputValue, optionsArray, handleChange, explanationHelperText, error, helperText }) { const classes = useStyles(); return ( - + {inputLabel} - {helperText && {helperText}} + {error && {helperText}} + {explanationHelperText && {explanationHelperText}} ); } diff --git a/src/main/www/src/components/UIComponents/Inputs/Input.js b/src/main/www/src/components/UIComponents/Inputs/Input.js index 7163227f..0434d0b0 100644 --- a/src/main/www/src/components/UIComponents/Inputs/Input.js +++ b/src/main/www/src/components/UIComponents/Inputs/Input.js @@ -51,7 +51,7 @@ export default function Input(props) { value={value} onChange={onChange} error={error} - helperText={helperText} + helperText={error && helperText} size="small" variant="outlined" className={classes.root} @@ -62,6 +62,7 @@ export default function Input(props) { className: classes.input, inputProps: { 'aria-labelledby': ariaLabel, + maxLength: 255, }, }} /> -- GitLab From 2a8d4fe0a22e8acc6f158aeceb9aad6b9bd11af0 Mon Sep 17 00:00:00 2001 From: "Zhou (Link) Fang" <43075439+linkfang@users.noreply.github.com> Date: Thu, 26 Aug 2021 16:12:21 -0400 Subject: [PATCH 12/14] Added content to step 2 (#294) * Fixed typos * Fixed org type display issue * Updated content for step 2 * Modified the anchor tag and fixed a typo --- .../CompanyInformation/CompanyInformation.js | 13 +++++++++---- .../CompanyInformation/CompanyInformationCompany.js | 1 - 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/www/src/components/Application/CompanyInformation/CompanyInformation.js b/src/main/www/src/components/Application/CompanyInformation/CompanyInformation.js index e66c04cc..938cbece 100644 --- a/src/main/www/src/components/Application/CompanyInformation/CompanyInformation.js +++ b/src/main/www/src/components/Application/CompanyInformation/CompanyInformation.js @@ -245,15 +245,20 @@ const CompanyInformation = ({ Please complete your company information below. This should be the legal name and address of your organization.

+

+ **** NOTE: Committers wishing to complete the Eclipse Foundation membership process should not use this form, + but instead should visit{' '} + + here + + . +

- + ); }; diff --git a/src/main/www/src/components/Application/CompanyInformation/CompanyInformationCompany.js b/src/main/www/src/components/Application/CompanyInformation/CompanyInformationCompany.js index 1c4743cc..8c4dc2ea 100644 --- a/src/main/www/src/components/Application/CompanyInformation/CompanyInformationCompany.js +++ b/src/main/www/src/components/Application/CompanyInformation/CompanyInformationCompany.js @@ -186,7 +186,6 @@ const CompanyInformationCompany = ({ formik, useStyles }) => { className={classes.textField} error={formik.touched.organization?.address?.city && Boolean(formik.errors.organization?.address?.country)} helperText={formik.touched.organization?.address?.city && formik.errors.organization?.address?.country} - oncha /> ); }} -- GitLab From 4a1c5f171bb8e2493950df2663cd747fc6e398ed Mon Sep 17 00:00:00 2001 From: "Zhou (Link) Fang" <43075439+linkfang@users.noreply.github.com> Date: Fri, 27 Aug 2021 08:30:47 -0400 Subject: [PATCH 13/14] Fixed can't skip a wg issue (#297) * Fixed can't skip a wg issue * Added a missing property back for updating formvalues --- .../src/components/Application/Application.js | 3 +- .../WorkingGroups/WorkingGroupsWrapper.js | 2 +- .../FormComponents/ValidationSchema.js | 35 ++++++++++--------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/main/www/src/components/Application/Application.js b/src/main/www/src/components/Application/Application.js index 695bfaf5..ac0f1270 100644 --- a/src/main/www/src/components/Application/Application.js +++ b/src/main/www/src/components/Application/Application.js @@ -80,6 +80,7 @@ export default function Application() { purchasingAndVAT, membershipLevel, 'membershipLevel-label': membershipLevelLabel, + workingGroups: formikWorkingGroups.values.workingGroups, signingAuthorityRepresentative: signingAuthorityRepresentative, }; setUpdatedFormValues(theNewValue); @@ -159,7 +160,7 @@ export default function Application() { setUpdatedFormValues({ ...updatedFormValues, workingGroups }); console.log('updated working groups: ', values); - if (values.isJoiningWG) { + if (!values.skipJoiningWG) { // If the user is joining at least 1 wg, then make related API call const setFieldValueObj = { fieldName: 'workingGroups', diff --git a/src/main/www/src/components/Application/WorkingGroups/WorkingGroupsWrapper.js b/src/main/www/src/components/Application/WorkingGroups/WorkingGroupsWrapper.js index 0d52be14..4ad4042e 100644 --- a/src/main/www/src/components/Application/WorkingGroups/WorkingGroupsWrapper.js +++ b/src/main/www/src/components/Application/WorkingGroups/WorkingGroupsWrapper.js @@ -67,7 +67,7 @@ const WorkingGroupsWrapper = ({ formik, formikOrgValue, fullWorkingGroupList, wo const handleClearData = () => { // if user check it, we need to delete all wgs in formik and db formik.values.workingGroups.map((item) => { - deleteData(currentFormId, END_POINT.working_groups, item.id, console.log, `Deleted ${item.workingGroup.label}`); + deleteData(currentFormId, END_POINT.working_groups, item.id, console.log, `Deleted ${item?.workingGroup?.label}`); return null; }); formik.setFieldValue('skipJoiningWG', true); diff --git a/src/main/www/src/components/UIComponents/FormComponents/ValidationSchema.js b/src/main/www/src/components/UIComponents/FormComponents/ValidationSchema.js index a9608258..3a29ddc1 100644 --- a/src/main/www/src/components/UIComponents/FormComponents/ValidationSchema.js +++ b/src/main/www/src/components/UIComponents/FormComponents/ValidationSchema.js @@ -89,22 +89,25 @@ export const validationSchema = [ // Third step - working groups yup.object().shape({ - workingGroups: yup.array().of( - yup.object().shape({ - workingGroup: yup - .object() - .nullable() - .required('Please enter/select a valid working group') - .test('workingGroup', 'Please enter/select a valid working group', function (selectedWG) { - const allWorkingGroups = this.options.parent?.allWorkingGroups; - const typedWG = this.options.parent?.['workingGroup-label']; - const isValid = allWorkingGroups?.includes(typedWG) && selectedWG?.label ? true : false; - return typedWG ? isValid : true; - }), - participationLevel: REQUIRED_MAX_YUP, - workingGroupRepresentative: CONTACT_YUP, - }) - ), + workingGroups: yup.array().when('skipJoiningWG', { + is: false, + then: yup.array().of( + yup.object().shape({ + workingGroup: yup + .object() + .nullable() + .required('Please enter/select a valid working group') + .test('workingGroup', 'Please enter/select a valid working group', function (selectedWG) { + const allWorkingGroups = this.options.parent?.allWorkingGroups; + const typedWG = this.options.parent?.['workingGroup-label']; + const isValid = allWorkingGroups?.includes(typedWG) && selectedWG?.label ? true : false; + return typedWG ? isValid : true; + }), + participationLevel: REQUIRED_MAX_YUP, + workingGroupRepresentative: CONTACT_YUP, + }) + ), + }), }), // Forth, signing Authority -- GitLab From af462babb5018e591e2c2c49f225e2e6cb14aaa2 Mon Sep 17 00:00:00 2001 From: "Zhou (Link) Fang" <43075439+linkfang@users.noreply.github.com> Date: Fri, 27 Aug 2021 09:07:36 -0400 Subject: [PATCH 14/14] Added a return to home button for 50x page (#295) --- .../www/src/components/ErrorPages/InternalError50x.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/www/src/components/ErrorPages/InternalError50x.js b/src/main/www/src/components/ErrorPages/InternalError50x.js index 3fd22e68..ff9f42f0 100644 --- a/src/main/www/src/components/ErrorPages/InternalError50x.js +++ b/src/main/www/src/components/ErrorPages/InternalError50x.js @@ -1,9 +1,14 @@ +import { Button } from "@material-ui/core"; + export default function InternalError50x() { return ( - <> +

An unexpected error occurred

Sorry, the page you are looking for is currently unavailable.

Please try again later.

- + +
); } -- GitLab