Unverified Commit e2815b8e authored by Zhou (Link)  Fang's avatar Zhou (Link) Fang Committed by GitHub
Browse files

Added the new form fields (#98)

* Added the new form fields

* integrated with new API call

* Added the API call for purchasing, VAT and signing authority

* fixed a typo and cleaned a few comments

* solved the conflicts

* fixed data did not sync up issue
parent 8d44f0dc
......@@ -50,8 +50,15 @@ export const CONTACT_TYPE = {
MARKETING: 'MARKETING',
ACCOUNTING: 'ACCOUNTING',
WORKING_GROUP: 'WORKING_GROUP',
SIGNING: 'SIGNING',
};
export const OPTIONS_FOR_PURCHASING_PROCES = [
{ label: 'Yes', value: 'yes' },
{ label: 'No', value: 'no' },
{ label: 'Not Applicable', value: 'na' },
];
export const END_POINT = {
organizations: 'organizations',
contacts: 'contacts',
......@@ -74,7 +81,7 @@ export function getCurrentMode() {
'//membership-staging.eclipse.org',
'//membership.eclipse.org/',
'//www.rem.docker/',
].some(value => {
].some((value) => {
return window.location.href.indexOf(value) !== -1;
});
......
......@@ -7,6 +7,7 @@ import {
getCurrentMode,
MODE_REACT_ONLY,
MODE_REACT_API,
OPTIONS_FOR_PURCHASING_PROCES,
} from '../Constants/Constants';
/**
......@@ -88,6 +89,27 @@ export function matchCompanyFields(existingOrganizationData) {
};
}
/**
* @param existingPurchasingAndVATData -
* Existing purchasing process and VAT data, fetched from server
*/
export function mapPurchasingAndVAT(existingPurchasingAndVATData) {
const currentOption = OPTIONS_FOR_PURCHASING_PROCES.find(
(item) =>
item.value === existingPurchasingAndVATData.purchase_order_required
);
return {
// Step1: purchasing process and VAT Info
id: existingPurchasingAndVATData?.id || '',
legalName: existingPurchasingAndVATData?.legal_name || '',
purchasingProcess: existingPurchasingAndVATData.purchase_order_required,
'purchasingProcess-label': currentOption,
vatNumber: existingPurchasingAndVATData.vat_number,
countryOfRegistration: existingPurchasingAndVATData.registration_country,
};
}
/**
* @param membershipLevel -
* Existing membershipLevel data, fetched from server
......@@ -118,8 +140,12 @@ export function matchContactFields(existingContactData) {
let existingAccoutingContact = existingContactData.find(
(el) => el.type === CONTACT_TYPE.ACCOUNTING
);
let existingSigningContact = existingContactData.find(
(el) => el.type === CONTACT_TYPE.SIGNING
);
return {
organizationContacts: {
member: {
id: existingCompanyContact?.id || '',
firstName: existingCompanyContact?.first_name || '',
......@@ -151,6 +177,15 @@ export function matchContactFields(existingContactData) {
existingAccoutingContact
),
},
},
signingAuthorityRepresentative: {
id: existingSigningContact?.id || '',
firstName: existingSigningContact?.first_name || '',
lastName: existingSigningContact?.last_name || '',
jobtitle: existingSigningContact?.job_title || '',
email: existingSigningContact?.email || '',
},
};
}
......@@ -229,15 +264,20 @@ export function matchCompanyFieldsToBackend(organizationData, formId) {
* @param userId - User Id fetched from the server when sign in, sotored in membership context, used for calling APIs
*/
export function matchMembershipLevelFieldsToBackend(
membershipLevel,
membershipLevelFormData,
formId,
userId
) {
return {
id: formId,
user_id: userId,
membership_level: membershipLevel,
signing_authority: true,
membership_level: membershipLevelFormData.membershipLevel,
signing_authority: true, //what does this do?
purchase_order_required:
membershipLevelFormData.purchasingAndVAT.purchasingProcess,
vat_number: membershipLevelFormData.purchasingAndVAT.vatNumber,
registration_country:
membershipLevelFormData.purchasingAndVAT.countryOfRegistration,
};
}
......@@ -338,17 +378,18 @@ export async function executeSendDataByStep(step, formData, formId, userId) {
formId
)
);
callSendData(
formId,
'',
matchMembershipLevelFieldsToBackend(formData, formId, userId)
);
break;
case 2:
callSendData(
formId,
'',
matchMembershipLevelFieldsToBackend(
formData.membershipLevel,
formId,
userId
)
matchMembershipLevelFieldsToBackend(formData, formId, userId)
);
break;
......@@ -363,6 +404,15 @@ export async function executeSendDataByStep(step, formData, formId, userId) {
break;
case 4:
callSendData(
formId,
END_POINT.contacts,
matchContactFieldsToBackend(
formData.signingAuthorityRepresentative,
CONTACT_TYPE.SIGNING,
formId
)
);
return;
default:
......
import { useContext, useEffect, useState } from 'react';
import MembershipContext from '../../../Context/MembershipContext';
import {
mapMembershipLevel,
mapPurchasingAndVAT,
matchCompanyFields,
matchContactFields,
} from '../../../Utils/formFunctionHelpers';
......@@ -14,8 +16,11 @@ import {
getCurrentMode,
MODE_REACT_ONLY,
MODE_REACT_API,
MEMBERSHIP_LEVELS,
} from '../../../Constants/Constants';
import CustomStepButton from '../../UIComponents/Button/CustomStepButton';
import CompanyInformationVAT from './CompanyInformationVAT';
import { makeStyles } from '@material-ui/core';
/**
* Wrapper for Contacts and Company components
......@@ -29,6 +34,15 @@ import CustomStepButton from '../../UIComponents/Button/CustomStepButton';
* library (such as "formik.values", "formik.setFieldValue");
* - formField: the form field in formModels/formFieldModel.js
*/
const useStyles = makeStyles(() => ({
textField: {
marginBottom: 14,
marginTop: 6,
backgroundColor: 'white',
},
}));
const CompanyInformation = ({ formik, isStartNewForm }) => {
const { currentFormId, furthestPage } = useContext(MembershipContext); // current chosen form id
const [loading, setLoading] = useState(true);
......@@ -103,7 +117,62 @@ const CompanyInformation = ({ formik, isStartNewForm }) => {
// Prefill Data --> Call the setFieldValue of Formik,
// to set representative field with the mapped data,
// if nested, it will automatically map the properties and values
formik.setFieldValue('representative', tempContacts);
formik.setFieldValue(
'representative',
tempContacts.organizationContacts
);
formik.setFieldValue(
'signingAuthorityRepresentative',
tempContacts.signingAuthorityRepresentative
);
}
setLoading(false);
});
} else {
setLoading(false);
}
};
const detectModeAndFetchMembershipLevel = () => {
let url_prefix_local;
let url_suffix_local = '';
if (getCurrentMode() === MODE_REACT_ONLY) {
url_prefix_local = 'membership_data';
url_suffix_local = '/form.json';
}
if (getCurrentMode() === MODE_REACT_API) {
url_prefix_local = API_PREFIX_FORM;
}
// If the current form exsits, and it is not creating a new form
if (currentFormId) {
fetch(url_prefix_local + `/${currentFormId}` + url_suffix_local, {
headers: FETCH_HEADER,
})
.then((resp) => resp.json())
.then((data) => {
if (data) {
// mapMembershipLevel(): Call the the function to map
// the retrived membership level backend data to fit frontend, and
// setFieldValue(): Prefill Data --> Call the setFieldValue of
// Formik, to set membershipLevel field with the mapped data
const tempMembershipLevel = mapMembershipLevel(
data[0]?.membership_level,
MEMBERSHIP_LEVELS
);
formik.setFieldValue(
'membershipLevel',
tempMembershipLevel.value
);
formik.setFieldValue(
'membershipLevel-label',
tempMembershipLevel
);
const tempPurchasingAndVAT = mapPurchasingAndVAT(data[0]);
formik.setFieldValue('purchasingAndVAT', tempPurchasingAndVAT);
}
setLoading(false);
});
......@@ -130,6 +199,7 @@ const CompanyInformation = ({ formik, isStartNewForm }) => {
// then it means this is the 1st time the user see this page
// need to GET the data
detectModeAndFetch();
detectModeAndFetchMembershipLevel();
} else {
// user already has the data, no need to do any API call
setLoading(false);
......@@ -151,8 +221,9 @@ const CompanyInformation = ({ formik, isStartNewForm }) => {
name and address of your organization.
</p>
<div className="align-center">
<CompanyInformationCompany formik={formik} />
<CompanyInformationCompany formik={formik} useStyles={useStyles} />
<CompanyInformationContacts formik={formik} />
<CompanyInformationVAT formik={formik} useStyles={useStyles} />
</div>
<CustomStepButton
......
import Input from '../../UIComponents/Inputs/Input';
import { formField } from '../../UIComponents/FormComponents/formFieldModel';
import Autocomplete from '@material-ui/lab/Autocomplete';
import { makeStyles, TextField } from '@material-ui/core';
import { TextField } from '@material-ui/core';
/**
* Render Oraganization selector (used React-Select)
......@@ -12,15 +12,7 @@ import { makeStyles, TextField } from '@material-ui/core';
* correct country list names)
*/
const useStyles = makeStyles(() => ({
textField: {
marginBottom: 14,
marginTop: 6,
backgroundColor: 'white',
},
}));
const CompanyInformationCompany = ({ formik }) => {
const CompanyInformationCompany = ({ formik, useStyles }) => {
const classes = useStyles();
const { organizationName, organizationTwitter, organizationAddress } =
formField;
......
......@@ -156,7 +156,7 @@ const Contacts = ({ formik }) => {
label="Same as member rep."
/>
<div className="row">
<div className="row margin-bottom-40">
{generateContacts(
companyRep,
'accounting-rep',
......
import Input from '../../UIComponents/Inputs/Input';
import { formField } from '../../UIComponents/FormComponents/formFieldModel';
import { TextField } from '@material-ui/core';
import Autocomplete from '@material-ui/lab/Autocomplete';
import { OPTIONS_FOR_PURCHASING_PROCES } from '../../../Constants/Constants';
const { purchasingProcess, vatRegistration } = formField;
export default function CompanyInformationVAT({ formik, useStyles }) {
const classes = useStyles();
return (
<>
<h4
className="fw-600 section-header"
id={`${purchasingProcess.name}-ctn`}
>
Purchasing Process
<span className="orange-star margin-left-5">*</span>
</h4>
<p>
Does your organization require a Purchase Order to facilitate payment of
your membership dues?
</p>
<div className="row">
<div className="col-md-12 margin-bottom-40">
<Autocomplete
id={purchasingProcess.name}
options={OPTIONS_FOR_PURCHASING_PROCES}
getOptionLabel={(option) => (option?.label ? option.label : '')}
getOptionSelected={(option, value) => option.value === value.value}
fullWidth={true}
onChange={(ev, value) => {
// this is only for display
formik.setFieldValue(
`${purchasingProcess.name}-label`,
value ? value : null
);
// this is the data will be actually used
formik.setFieldValue(
purchasingProcess.name,
value ? value.value : null
);
}}
value={
formik.values.purchasingAndVAT['purchasingProcess-label']
? formik.values.purchasingAndVAT['purchasingProcess-label']
: null
}
renderInput={(params) => {
params.inputProps = {
...params.inputProps,
'aria-labelledby': `${purchasingProcess.name}-ctn`,
};
return (
<TextField
{...params}
label={purchasingProcess.label}
placeholder={purchasingProcess.placeholder}
variant="outlined"
size="small"
required={true}
className={classes.textField}
/>
);
}}
/>
</div>
</div>
<h4 className="fw-600" id="vatRegistration">
VAT Registration
</h4>
<p>
If your organization is registered for VAT in the European Union, please
provide the following:
</p>
<div className="row">
<div className="col-md-12">
<Input
name={vatRegistration.vatNumber.name}
labelName={vatRegistration.vatNumber.label}
placeholder={vatRegistration.vatNumber.placeholder}
requiredMark={false}
value={formik.values.purchasingAndVAT.vatNumber}
onChange={formik.handleChange}
ariaLabel={`vatRegistration`}
/>
</div>
<div className="col-md-12">
<Input
name={vatRegistration.countryOfRegistration.name}
labelName={vatRegistration.countryOfRegistration.label}
placeholder={vatRegistration.countryOfRegistration.placeholder}
requiredMark={false}
value={formik.values.purchasingAndVAT.countryOfRegistration}
onChange={formik.handleChange}
ariaLabel={`vatRegistration`}
/>
</div>
</div>
</>
);
}
......@@ -2,10 +2,7 @@ import { useContext, useState } from 'react';
import { Switch, Route, Redirect } from 'react-router-dom';
import { useFormik } from 'formik';
import SignIn from './SignIn/SignIn';
import {
COMPANY_INFORMATION,
PAGE_STEP,
} from '../../Constants/Constants';
import { COMPANY_INFORMATION, PAGE_STEP } from '../../Constants/Constants';
import {
formField,
initialValues,
......@@ -36,11 +33,16 @@ export default function Main() {
history.push(nextPage);
};
const submitForm = (pageIndex, nextPage) => {
// do something for submiting
// ...
const updateMembershipLevelForm = (values) => {
values.forEach((item) => {
formikMembershipLevel.setFieldValue(item.field, item.value);
});
};
goToNextStep(pageIndex, nextPage);
const updateCompanyInfoForm = (values) => {
values.forEach((item) => {
formikCompanyInfo.setFieldValue(item.field, item.value);
});
};
const formikCompanyInfo = useFormik({
......@@ -50,14 +52,33 @@ export default function Main() {
// update the organization values
const organization = values.organization;
const representative = values.representative;
setUpdatedFormValues({
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);
executeSendDataByStep(1, values, currentFormId, currentUser.name);
const valueToUpdateFormik = [
{ field: 'purchasingAndVAT', value: purchasingAndVAT },
{ field: 'membershipLevel', value: membershipLevel },
{ field: 'membershipLevel-label', value: membershipLevelLabel },
];
// set valueToUpdateFormik to membershipLevel formik to make sure the value is up to date
updateMembershipLevelForm(valueToUpdateFormik);
executeSendDataByStep(1, theNewValue, currentFormId, currentUser.name);
goToNextStep(1, '/membership-level');
},
......@@ -69,9 +90,21 @@ export default function Main() {
onSubmit: (values) => {
// update the membershipLevel values
const membershipLevel = values.membershipLevel;
setUpdatedFormValues({ ...updatedFormValues, 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(2, '/working-groups');
......@@ -104,6 +137,18 @@ export default function Main() {
...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);
executeSendDataByStep(4, values, currentFormId, currentUser.name);
goToNextStep(4, '/review');
},
});
......@@ -130,12 +175,12 @@ export default function Main() {
return (
<div className="container eclipseFdn-membership-webform">
<>
{window.location.pathname === '/' ||
window.location.pathname === '/sign-in' ? (
{window.location.hash === '/' ||
window.location.hash === '#sign-in' ? (
<SignInIntroduction />
) : null}
{window.location.pathname !== '/submitted' && renderStepper()}
{window.location.hash !== '#submitted' && renderStepper()}
<Switch>
<Route exact path="/">
......@@ -174,6 +219,7 @@ export default function Main() {
formik={formikMembershipLevel}
isStartNewForm={isStartNewForm}
furthestPage={furthestPage}
updatedFormValues={updatedFormValues}
/>
) : (
<Redirect to={furthestPage.pathName} />
......@@ -194,7 +240,10 @@ export default function Main() {
<Route path="/signing-authority">
{furthestPage.index >= 4 ? (
<SigningAuthority formik={formikSigningAuthority} />
<SigningAuthority
formik={formikSigningAuthority}
updatedFormValues={updatedFormValues}
/>
) : (
<Redirect to={furthestPage.pathName} />
)}
......@@ -202,7 +251,7 @@ export default function Main() {
<Route path="/review">
{furthestPage.index >= 5 ? (
<Review values={updatedFormValues} submitForm={submitForm} />
<Review values={updatedFormValues} submitForm={goToNextStep} />
) : (
<Redirect to={furthestPage.pathName} />
)}
......
import { useContext, useEffect, useState } from 'react';
import MembershipLevelFeeTable from './MembershipLevelFeeTable';
import MembershipContext from '../../../Context/MembershipContext';
import Loading from '../../UIComponents/Loading/Loading';
import { mapMembershipLevel } from '../../../Utils/formFunctionHelpers';
import {
API_PREFIX_FORM,
FETCH_HEADER,
MEMBERSHIP_LEVELS,
newForm_tempId,
getCurrentMode,
MODE_REACT_ONLY,
MODE_REACT_API,
} from '../../../Constants/Constants';
import { makeStyles, TextField } from '@material-ui/core';
import Autocomplete from '@material-ui/lab/Autocomplete';
import CustomStepButton from '../../UIComponents/Button/CustomStepButton';
import { formField } from '../../UIComponents/FormComponents/formFieldModel';
import { MEMBERSHIP_LEVELS } from '../../../Constants/Constants';
/**