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

Replaced input components (#70)

parent 73c5f451
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"@material-ui/core": "^4.11.4", "@material-ui/core": "^4.11.4",
"@material-ui/lab": "^4.0.0-alpha.58",
"@testing-library/jest-dom": "^4.2.4", "@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0", "@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1", "@testing-library/user-event": "^7.2.1",
...@@ -18,6 +19,7 @@ ...@@ -18,6 +19,7 @@
"react": "^17.0.0", "react": "^17.0.0",
"react-app-polyfill": "^2.0.0", "react-app-polyfill": "^2.0.0",
"react-dom": "^17.0.0", "react-dom": "^17.0.0",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3", "react-scripts": "4.0.3",
"swagger-repo": "^2.0.0-rc.15", "swagger-repo": "^2.0.0-rc.15",
"typescript": "^4.3.2", "typescript": "^4.3.2",
......
...@@ -10,6 +10,9 @@ ...@@ -10,6 +10,9 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
html {
font-size: 14px;
}
.eclipseFdn-membership-webform { .eclipseFdn-membership-webform {
/* Stepper */ /* Stepper */
} }
...@@ -102,6 +105,20 @@ ...@@ -102,6 +105,20 @@
position: relative; position: relative;
padding-top: 30px; padding-top: 30px;
} }
.eclipseFdn-membership-webform .step a {
text-decoration: none;
color: inherit;
}
.eclipseFdn-membership-webform .step a:visited {
color: inherit;
}
.eclipseFdn-membership-webform .btn a {
text-decoration: none;
color: inherit;
}
.eclipseFdn-membership-webform .btn a:visited {
color: inherit;
}
.eclipseFdn-membership-webform .step-span { .eclipseFdn-membership-webform .step-span {
width: 50px; width: 50px;
height: 50px; height: 50px;
...@@ -133,6 +150,13 @@ ...@@ -133,6 +150,13 @@
background: #404040 50% no-repeat; background: #404040 50% no-repeat;
color: #fff; color: #fff;
} }
.eclipseFdn-membership-webform .button-container a {
text-decoration: none;
}
.eclipseFdn-membership-webform .button-container button {
width: 80px;
margin: 0 14px;
}
@media (min-width: 992px) { @media (min-width: 992px) {
.eclipseFdn-membership-webform .step { .eclipseFdn-membership-webform .step {
width: calc(100% / 6); width: calc(100% / 6);
......
import React, { useState } from 'react'; import { useState } from 'react';
import './App.css'; import './App.css';
import AppFooter from './components/UIComponents/layout/AppFooter'; import AppFooter from './components/UIComponents/layout/AppFooter';
import AppHeader from './components/UIComponents/layout/AppHeader'; import AppHeader from './components/UIComponents/layout/AppHeader';
import FormWrapper from './components/UIComponents/FormPreprocess/FormWrapper';
import MembershipContext from './Context/MembershipContext'; import MembershipContext from './Context/MembershipContext';
import { createMuiTheme, ThemeProvider } from '@material-ui/core'; import { createMuiTheme, ThemeProvider } from '@material-ui/core';
import { BrowserRouter as Router } from 'react-router-dom';
import Main from './components/Pages/Main';
const theme = createMuiTheme({ const theme = createMuiTheme({
palette: { palette: {
primary: { primary: {
main: '#f7941e', main: '#f7941e',
contrastText: '#fff', // for button text color
}, },
}, },
}); });
...@@ -17,20 +19,31 @@ const theme = createMuiTheme({ ...@@ -17,20 +19,31 @@ const theme = createMuiTheme({
const App = () => { const App = () => {
const [currentUser, setCurrentUser] = useState(null); const [currentUser, setCurrentUser] = useState(null);
const [currentFormId, setCurrentFormId] = useState(''); const [currentFormId, setCurrentFormId] = useState('');
const [furthestPage, setFurthestPage] = useState({
index: 0,
pathName: '/signIn',
});
const membershipContextValue = { const membershipContextValue = {
currentUser, currentUser,
setCurrentUser: (val) => setCurrentUser(val), setCurrentUser: (val) => setCurrentUser(val),
currentFormId, currentFormId,
setCurrentFormId: (val) => setCurrentFormId(val), setCurrentFormId: (val) => setCurrentFormId(val),
furthestPage,
setFurthestPage,
}; };
return ( return (
<div className="App"> <div className="App">
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<AppHeader /> <AppHeader />
<MembershipContext.Provider value={membershipContextValue}> <MembershipContext.Provider value={membershipContextValue}>
<FormWrapper /> <Router>
<Main
furthestPage={furthestPage}
setFurthestPage={setFurthestPage}
/>
</Router>
</MembershipContext.Provider> </MembershipContext.Provider>
<AppFooter /> <AppFooter />
</ThemeProvider> </ThemeProvider>
......
...@@ -29,7 +29,6 @@ export const FETCH_HEADER = { ...@@ -29,7 +29,6 @@ export const FETCH_HEADER = {
}; };
export const membership_levels = [ export const membership_levels = [
{ label: 'Select a level', value: '' },
{ label: 'Strategic Member', value: 'strategic' }, { label: 'Strategic Member', value: 'strategic' },
{ {
label: 'Contributing Member (formerly referred to as Solutions Members)', label: 'Contributing Member (formerly referred to as Solutions Members)',
...@@ -38,12 +37,12 @@ export const membership_levels = [ ...@@ -38,12 +37,12 @@ export const membership_levels = [
{ label: 'Associate Member', value: 'associate' }, { label: 'Associate Member', value: 'associate' },
]; ];
export const fakeChildrenArray = [ export const PAGE_STEP = [
{ props: { label: COMPANY_INFORMATION } }, { props: { label: COMPANY_INFORMATION, pathName: '/company-info' } },
{ props: { label: MEMBERSHIP_LEVEL } }, { props: { label: MEMBERSHIP_LEVEL, pathName: '/membership-level' } },
{ props: { label: WORKING_GROUPS } }, { props: { label: WORKING_GROUPS, pathName: '/working-groups' } },
{ props: { label: SIGNING_AUTHORITY } }, { props: { label: SIGNING_AUTHORITY, pathName: '/signing-authority' } },
{ props: { label: REVIEW } }, { props: { label: REVIEW, pathName: '/review' } },
]; ];
export const contact_type = { export const contact_type = {
......
...@@ -8,11 +8,14 @@ import React from 'react'; ...@@ -8,11 +8,14 @@ import React from 'react';
* It is simliar to state, but you can export and import anywhere, * It is simliar to state, but you can export and import anywhere,
* no need to pass all the way down to the child component * no need to pass all the way down to the child component
*/ */
const MembershipContext = React.createContext({ const MembershipContext = React.createContext({
currentUser: {}, currentUser: {},
setCurrentUser: () => {}, setCurrentUser: () => {},
currentFormId: '', currentFormId: '',
setCurrentFormId: () => {}, setCurrentFormId: () => {},
furthestPage: '',
setFurthestPage: '',
}); });
export default MembershipContext; export default MembershipContext;
...@@ -72,23 +72,17 @@ export function matchCompanyFields(existingOrganizationData) { ...@@ -72,23 +72,17 @@ export function matchCompanyFields(existingOrganizationData) {
return { return {
// Step1: company Info // Step1: company Info
id: existingOrganizationData?.id || '', id: existingOrganizationData?.id || '',
legalName: legalName: existingOrganizationData?.legal_name || '',
{
value: existingOrganizationData?.legal_name || '',
label: existingOrganizationData?.legal_name || '',
address: existingOrganizationData?.address || '',
twitterHandle: existingOrganizationData?.twitter_handle || '',
} || '',
address: { address: {
id: existingOrganizationData?.address.id || '', id: existingOrganizationData?.address.id || '',
street: existingOrganizationData?.address.street || '', street: existingOrganizationData?.address.street || '',
city: existingOrganizationData?.address.city || '', city: existingOrganizationData?.address.city || '',
provinceOrState: existingOrganizationData?.address.province_state || '', provinceOrState: existingOrganizationData?.address.province_state || '',
country: country: {
{ label: existingOrganizationData?.address.country || '',
label: existingOrganizationData?.address.country, value: existingOrganizationData?.address.country || '',
value: existingOrganizationData?.address.country, },
} || '', 'country-label': existingOrganizationData?.address.country || '',
postalCode: existingOrganizationData?.address.postal_code || '', postalCode: existingOrganizationData?.address.postal_code || '',
}, },
twitterHandle: existingOrganizationData?.twitter_handle || '', twitterHandle: existingOrganizationData?.twitter_handle || '',
......
...@@ -4,8 +4,8 @@ import { ...@@ -4,8 +4,8 @@ import {
matchCompanyFields, matchCompanyFields,
matchContactFields, matchContactFields,
} from '../../../Utils/formFunctionHelpers'; } from '../../../Utils/formFunctionHelpers';
import Company from './CompanyInformationCompany'; import CompanyInformationCompany from './CompanyInformationCompany';
import Contacts from './CompanyInformationContacts'; import CompanyInformationContacts from './CompanyInformationContacts';
import Loading from '../../UIComponents/Loading/Loading'; import Loading from '../../UIComponents/Loading/Loading';
import { import {
end_point, end_point,
...@@ -16,6 +16,8 @@ import { ...@@ -16,6 +16,8 @@ import {
MODE_REACT_ONLY, MODE_REACT_ONLY,
MODE_REACT_API, MODE_REACT_API,
} from '../../../Constants/Constants'; } from '../../../Constants/Constants';
import CustomStepButton from '../../UIComponents/Button/CustomStepButton';
import { initialValues } from '../../UIComponents/FormComponents/formFieldModel';
/** /**
* Wrapper for Contacts and Company components * Wrapper for Contacts and Company components
...@@ -24,25 +26,24 @@ import { ...@@ -24,25 +26,24 @@ import {
* with fetch and prefill data operation. * with fetch and prefill data operation.
* *
* Props: * Props:
* - otherProps: any other props passing down from MultiStepForm and * - otherProps: any other props passing down from
* FormikStepper components, including formik props of formik * FormikStepper components, including formik props of formik
* library (such as "formik.values", "formik.setFieldValue"); * library (such as "formik.values", "formik.setFieldValue");
* - formField: the form field in formModels/formFieldModel.js * - formField: the form field in formModels/formFieldModel.js
*/ */
const CompanyInformation = ({ formField, ...otherProps }) => { const CompanyInformation = ({ formik }) => {
const { currentFormId } = useContext(MembershipContext); // current chosen form id const { currentFormId } = useContext(MembershipContext); // current chosen form id
const formValues = otherProps.parentState.formik.values; // current form values
const { setFieldValue } = otherProps.parentState.formik;
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
// Fetch data only once and prefill data, const detectModeAndFetch = () => {
// as long as currentFormId and setFieldValue
// Function does not change, will not cause re-render again
useEffect(() => {
// Once we have API set up ready, we don't need the // Once we have API set up ready, we don't need the
// fake data anymore, and can remove these pre-process. // fake data anymore, and can remove these pre-process.
// it is mainly for if running the application // it is mainly for if running the application
// only react without server. // only react without server.
// just for React only testing.
// let currentFormId = 'form_1';
let url_prefix_local; let url_prefix_local;
let url_suffix_local = ''; let url_suffix_local = '';
// If running on localhost:3000 // If running on localhost:3000
...@@ -50,14 +51,12 @@ const CompanyInformation = ({ formField, ...otherProps }) => { ...@@ -50,14 +51,12 @@ const CompanyInformation = ({ formField, ...otherProps }) => {
url_prefix_local = 'membership_data'; // --> public/membership_data/ url_prefix_local = 'membership_data'; // --> public/membership_data/
url_suffix_local = '.json'; // --> it is the fake json file url_suffix_local = '.json'; // --> it is the fake json file
} }
// If running on localhost:8090 or any other not on localhost:3000 // If running on localhost:8090 or any other not on localhost:3000
// Once we have the API ready running on production, // Once we have the API ready running on production,
// will use the correct domain name rather than localhost:8090 // will use the correct domain name rather than localhost:8090
if (getCurrentMode() === MODE_REACT_API) { if (getCurrentMode() === MODE_REACT_API) {
url_prefix_local = api_prefix_form; url_prefix_local = api_prefix_form;
} }
// If the current form exsits, and it is not creating a new form // If the current form exsits, and it is not creating a new form
if (currentFormId && currentFormId !== newForm_tempId) { if (currentFormId && currentFormId !== newForm_tempId) {
// Using promise pool, because in first step, // Using promise pool, because in first step,
...@@ -78,7 +77,6 @@ const CompanyInformation = ({ formField, ...otherProps }) => { ...@@ -78,7 +77,6 @@ const CompanyInformation = ({ formField, ...otherProps }) => {
{ headers: FETCH_HEADER } { headers: FETCH_HEADER }
), ),
]; ];
Promise.all(pool) Promise.all(pool)
.then((res) => Promise.all(res.map((r) => r.json()))) .then((res) => Promise.all(res.map((r) => r.json())))
.then(([organizations, contacts]) => { .then(([organizations, contacts]) => {
...@@ -94,7 +92,8 @@ const CompanyInformation = ({ formField, ...otherProps }) => { ...@@ -94,7 +92,8 @@ const CompanyInformation = ({ formField, ...otherProps }) => {
// organization field with the mapped data, // organization field with the mapped data,
// if nested, it will automatically map the // if nested, it will automatically map the
// properties and values // properties and values
setFieldValue('organization', tempOrg); console.log(tempOrg);
formik.setFieldValue('organization', tempOrg);
} }
if (contacts.length) { if (contacts.length) {
// Call the the function to map the retrived contacts // Call the the function to map the retrived contacts
...@@ -104,14 +103,27 @@ const CompanyInformation = ({ formField, ...otherProps }) => { ...@@ -104,14 +103,27 @@ const CompanyInformation = ({ formField, ...otherProps }) => {
// Prefill Data --> Call the setFieldValue of Formik, // Prefill Data --> Call the setFieldValue of Formik,
// to set representative field with the mapped data, // to set representative field with the mapped data,
// if nested, it will automatically map the properties and values // if nested, it will automatically map the properties and values
setFieldValue('representative', tempContacts); formik.setFieldValue('representative', tempContacts);
} }
setLoading(false); setLoading(false);
}); });
} else if (currentFormId === newForm_tempId) {
formik.setFieldValue('representative', initialValues.representative);
formik.setFieldValue('organization', initialValues.organization);
setLoading(false);
} else { } else {
setLoading(false); setLoading(false);
} }
}, [currentFormId, setFieldValue]); };
// Fetch data only once and prefill data,
// as long as currentFormId and setFieldValue
// Function does not change, will not cause re-render again
useEffect(() => {
setLoading(true);
detectModeAndFetch();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentFormId]);
// If it is in loading status, // If it is in loading status,
// only return a loading spinning // only return a loading spinning
...@@ -120,17 +132,23 @@ const CompanyInformation = ({ formField, ...otherProps }) => { ...@@ -120,17 +132,23 @@ const CompanyInformation = ({ formField, ...otherProps }) => {
} }
return ( return (
<> <form onSubmit={formik.handleSubmit}>
<h1 className="fw-600 h2">Company Information</h1> <h1 className="fw-600 h2">Company Information</h1>
<p> <p>
Please complete your company information below. This should be the legal Please complete your company information below. This should be the legal
name and address of your organization. name and address of your organization.
</p> </p>
<div className="align-center"> <div className="align-center">
<Company /> <CompanyInformationCompany formik={formik} />
<Contacts formValues={formValues} formField={formField} /> <CompanyInformationContacts formik={formik} />
</div> </div>
</>
<CustomStepButton
previousPage=""
nextPage="/membership-level"
pageIndex={1}
/>
</form>
); );
}; };
......
import React from 'react'; import React from 'react';
import CustomSelectWrapper from '../../UIComponents/Inputs/CustomSelect/CustomSelectWrapper';
import DefaultSelect from '../../UIComponents/Inputs/CustomSelect/DefaultSelect';
import CustomAsyncSelect from '../../UIComponents/Inputs/CustomSelect/CustomAsyncSelect';
import Input from '../../UIComponents/Inputs/Input'; import Input from '../../UIComponents/Inputs/Input';
import { formField } from '../../UIComponents/FormComponents/formModels/formFieldModel'; import { formField } from '../../UIComponents/FormComponents/formFieldModel';
import { companies } from '../../../Constants/Constants'; import Autocomplete from '@material-ui/lab/Autocomplete';
import { makeStyles, TextField } from '@material-ui/core';
/** /**
* Render Oraganization selector (used React-Select) * Render Oraganization selector (used React-Select)
...@@ -14,12 +12,20 @@ import { companies } from '../../../Constants/Constants'; ...@@ -14,12 +12,20 @@ import { companies } from '../../../Constants/Constants';
* and country-list library of updated * and country-list library of updated
* correct country list names) * correct country list names)
*/ */
const Company = () => {
const { const useStyles = makeStyles(() => ({
organizationName, textField: {
organizationTwitter, marginBottom: 14,
organizationAddress, marginTop: 6,
} = formField; backgroundColor: 'white',
},
}));
const CompanyInformationCompany = ({ formik }) => {
const classes = useStyles();
const { organizationName, organizationTwitter, organizationAddress } =
formField;
// get country list library and map as option pass to the React-Select // get country list library and map as option pass to the React-Select
const countryList = require('country-list') const countryList = require('country-list')
.getNames() .getNames()
...@@ -28,14 +34,17 @@ const Company = () => { ...@@ -28,14 +34,17 @@ const Company = () => {
return ( return (
<> <>
<h2 className="fw-600 h4" id={organizationName.name}> <h2 className="fw-600 h4" id={organizationName.name}>
{' '} Organization <span className="orange-star">*</span>
Organization <span className="orange-star">*</span>{' '}
</h2> </h2>
<CustomSelectWrapper
<Input
name={organizationName.name} name={organizationName.name}
labelName={organizationName.label}
placeholder={organizationName.placeholder}
ariaLabel={organizationName.name} ariaLabel={organizationName.name}
srcData={companies} requiredMark={true}
renderComponent={CustomAsyncSelect} value={formik.values.organization.legalName}
onChange={formik.handleChange}
/> />
<div className="row"> <div className="row">
<div className="col-md-8"> <div className="col-md-8">
...@@ -43,11 +52,17 @@ const Company = () => { ...@@ -43,11 +52,17 @@ const Company = () => {
name={organizationTwitter.name} name={organizationTwitter.name}
labelName={organizationTwitter.label} labelName={organizationTwitter.label}
placeholder={organizationTwitter.placeholder} placeholder={organizationTwitter.placeholder}
ariaLabel={organizationName.name}
requiredMark={true}
value={formik.values.organization.twitterHandle}
onChange={formik.handleChange}
/> />
</div> </div>
</div> </div>
<h4 className="fw-600">Address</h4> <h4 className="fw-600" id={`${organizationName.name}-address`}>
Address
</h4>
<div className="row"> <div className="row">
<div className="col-md-16"> <div className="col-md-16">
<Input <Input
...@@ -55,6 +70,9 @@ const Company = () => { ...@@ -55,6 +70,9 @@ const Company = () => {
labelName={organizationAddress.street.label} labelName={organizationAddress.street.label}
placeholder={organizationAddress.street.placeholder} placeholder={organizationAddress.street.placeholder}
requiredMark={true} requiredMark={true}
value={formik.values.organization.address.street}
onChange={formik.handleChange}
ariaLabel={`${organizationName.name}-address`}
/> />
</div> </div>