Commit 88aae205 authored by Martin Lowe's avatar Martin Lowe 🇨🇦
Browse files

Merge remote-tracking branch 'origin/dev' into malowe/master/v1.4.4-merge

parents f70372d9 cb0e70cb
Pipeline #3107 passed with stage
......@@ -60,16 +60,12 @@ public interface PeopleAPI {
@QueryParam("project_relation")
public abstract String getRelation();
@Nullable
@QueryParam("is_not_expired")
public abstract Boolean getIsNotExpired();
@Nullable
@QueryParam("ids")
public abstract List<String> getIds();
public static Builder builder() {
return new AutoValue_PeopleAPI_PeopleRequestParams.Builder().setIsNotExpired(false);
return new AutoValue_PeopleAPI_PeopleRequestParams.Builder();
}
@AutoValue.Builder
......@@ -89,8 +85,6 @@ public interface PeopleAPI {
public abstract Builder setIds(@Nullable List<String> ids);
public abstract Builder setIsNotExpired(@Nullable Boolean isNotExpired);
public abstract PeopleRequestParams build();
}
}
......
......@@ -250,27 +250,33 @@ public class FoundationDBOrganizationService implements OrganizationsService {
params.add("fName", fName.orElse(null));
params.add("lName", lName.orElse(null));
return cache.get(orgID, params, OrganizationContactData.class,
() -> middleware.getAll(i -> orgAPI.getOrganizationContactsWithSearch(orgID, i,
OrganizationRequestParams.builder().setRelation(role.orElse(null))
.setFirstName(fName.orElse(null)).setLastName(lName.orElse(null))
.setEmail(mail.orElse(null)).build()),
() -> middleware.getAll(
i -> orgAPI.getOrganizationContactsWithSearch(orgID, i,
OrganizationRequestParams.builder().setRelation(role.orElse(null))
.setFirstName(fName.orElse(null)).setLastName(lName.orElse(null))
.setEmail(mail.orElse(null)).setIsNotExpired(false).build()),
OrganizationContactData.class));
}
@Override
public Optional<List<OrganizationContactData>> getOrganizationContacts(String orgID, String userName) {
return cache.get(orgID, new MultivaluedMapImpl<>(), OrganizationContactData.class, () -> middleware.getAll(
i -> orgAPI.getOrganizationContact(orgID, userName, i, OrganizationRequestParams.builder().build()),
OrganizationContactData.class));
return cache.get(orgID, new MultivaluedMapImpl<>(), OrganizationContactData.class,
() -> middleware.getAll(
i -> orgAPI.getOrganizationContact(orgID, userName, i,
OrganizationRequestParams.builder().setIsNotExpired(false).build()),
OrganizationContactData.class));
}
@Override
public Optional<List<OrganizationContactData>> getOrganizationContacts(String userName) {
return cache.get(userName, new MultivaluedMapImpl<>(), OrganizationContactData.class,
() -> middleware.getAll(
i -> orgAPI.getOrganizationContacts(i,
OrganizationRequestParams.builder().setPersonID(userName).build()),
OrganizationContactData.class));
return cache
.get(userName, new MultivaluedMapImpl<>(), OrganizationContactData.class,
() -> middleware.getAll(
i -> orgAPI
.getOrganizationContacts(i,
OrganizationRequestParams.builder().setPersonID(userName)
.setIsNotExpired(false).build()),
OrganizationContactData.class));
}
@Override
......@@ -278,11 +284,14 @@ public class FoundationDBOrganizationService implements OrganizationsService {
MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
params.add(FoundationDBParameterNames.USER_NAME.getName(), userName);
params.add(FoundationDBParameterNames.RELATION.getName(), role);
Optional<List<OrganizationContactData>> contacts = cache.get(orgID, params, OrganizationContactData.class,
() -> middleware.getAll(
i -> orgAPI.getOrganizationContact(orgID, userName, i,
OrganizationRequestParams.builder().setRelation(role).build()),
OrganizationContactData.class));
Optional<List<OrganizationContactData>> contacts = cache
.get(orgID, params, OrganizationContactData.class,
() -> middleware.getAll(
i -> orgAPI
.getOrganizationContact(orgID, userName, i,
OrganizationRequestParams.builder().setRelation(role)
.setIsNotExpired(false).build()),
OrganizationContactData.class));
// if we have results, then the relation exists for user
return contacts.isPresent() && !contacts.get().isEmpty();
}
......@@ -373,8 +382,10 @@ public class FoundationDBOrganizationService implements OrganizationsService {
params.add(MembershipFormAPIParameterNames.USER_ID.getName(), userName);
return cache
.get(orgID + "-access", params, OrganizationContactData.class,
() -> middleware.getAll(i -> orgAPI.getOrganizationContact(orgID, userName, i,
OrganizationRequestParams.builder().build()), OrganizationContactData.class))
() -> middleware.getAll(
i -> orgAPI.getOrganizationContact(orgID, userName, i,
OrganizationRequestParams.builder().setIsNotExpired(false).build()),
OrganizationContactData.class))
.orElse(Collections.emptyList()).stream()
.map(c -> OrganizationalUserType.valueOfChecked(c.getRelation())).collect(Collectors.toList());
}
......@@ -413,7 +424,8 @@ public class FoundationDBOrganizationService implements OrganizationsService {
new URI(info.getCompanyUrl());
out.setWebsite(info.getCompanyUrl());
} catch (URISyntaxException e) {
LOGGER.debug("Error while converting URL for organization '{}', leaving blank", info.getOrganizationID(), e);
LOGGER.debug("Error while converting URL for organization '{}', leaving blank",
info.getOrganizationID(), e);
}
}
......
......@@ -226,8 +226,10 @@ html {
.portal-login-page .portal-login-image {
position: fixed;
z-index: -10;
width: 110%;
height: 110%;
left: -30px;
top: -30px;
right: -30px;
bottom: -30px;
background-image: url('assets/images/placeholderImg.jpg');
background-position: center;
background-size: cover;
......
import {
FETCH_METHOD,
CONTACT_TYPE,
END_POINT,
API_PREFIX_FORM,
FETCH_HEADER,
getCurrentMode,
......@@ -301,146 +300,7 @@ export function matchWGFieldsToBackend(eachWorkingGroupData, formId) {
};
}
//== EXECUTE Send Data function
/**
* @param step - The current step that is sending data
* @param formData - Filled whole form data stored in formik context
* @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,
setFieldValueObj,
updateFormValuesObj,
callbackFunc
) {
switch (step) {
case 1:
callSendData(
formId,
END_POINT.organizations,
matchCompanyFieldsToBackend(formData.organization, formId),
step,
{
fieldName: setFieldValueObj.fieldName.organization,
method: setFieldValueObj.method,
},
updateFormValuesObj
);
callSendData(
formId,
END_POINT.contacts,
matchContactFieldsToBackend(formData.representative.member, CONTACT_TYPE.COMPANY, formId),
step,
{
fieldName: setFieldValueObj.fieldName.member,
method: setFieldValueObj.method,
},
updateFormValuesObj
);
callSendData(
formId,
END_POINT.contacts,
matchContactFieldsToBackend(formData.representative.marketing, CONTACT_TYPE.MARKETING, formId),
step,
{
fieldName: setFieldValueObj.fieldName.marketing,
method: setFieldValueObj.method,
},
updateFormValuesObj
);
callSendData(
formId,
END_POINT.contacts,
matchContactFieldsToBackend(formData.representative.accounting, CONTACT_TYPE.ACCOUNTING, formId),
step,
{
fieldName: setFieldValueObj.fieldName.accounting,
method: setFieldValueObj.method,
},
updateFormValuesObj
);
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,
updateFormValuesObj,
index
);
});
}
break;
case 2:
callSendData(formId, '', matchMembershipLevelFieldsToBackend(formData, formId, userId), step);
break;
case 3:
formData.workingGroups.forEach((item, index) => {
callSendData(
formId,
END_POINT.working_groups,
matchWGFieldsToBackend(item, formId),
step,
setFieldValueObj,
updateFormValuesObj,
index
);
});
break;
case 4:
callSendData(
formId,
END_POINT.contacts,
matchContactFieldsToBackend(formData.signingAuthorityRepresentative, CONTACT_TYPE.SIGNING, formId),
step,
setFieldValueObj,
updateFormValuesObj
);
break;
case 5:
callSendData(formId, END_POINT.complete, false, step, setFieldValueObj, '', '', callbackFunc);
break;
default:
return;
}
}
/**
* @param formId - Form Id fetched from the server, sotored in membership context, used for calling APIs
* @param endpoint - To which endpoint the fetch is calling to backend:
* /form/{id}, /form/{id}/organizations/{id}, /form/{id}/contacts/{id}, /form/{id}/working_groups/{id}
* @param dataBody - The data body passed to server, normally is the filled form data to be saved
* If empty, is creating a new entity, use POST method;
* If has value, is fetched from server, use PUT or DELETE;
*/
function callSendData(
formId,
endpoint = '',
dataBody,
stepNum,
setFieldValueObj,
updateFormValuesObj,
index,
callbackFunc
) {
export function fetchWrapperForm(formId, endpoint = '', dataBody, onSuccess) {
const entityId = dataBody.id ? dataBody.id : '';
const method = dataBody.id ? FETCH_METHOD.PUT : FETCH_METHOD.POST;
......@@ -454,88 +314,35 @@ function callSendData(
url = API_PREFIX_FORM + `/${formId}/${endpoint}/${entityId}`;
}
delete dataBody.id;
// Remove the id without impact on source/original data
const { id, ...sanitizedBody } = dataBody;
if (getCurrentMode() === MODE_REACT_ONLY) {
!isProd && console.log(`You called ${url} with Method ${method} and data body is:`);
!isProd && console.log(JSON.stringify(dataBody));
!isProd && console.log(JSON.stringify(sanitizedBody));
}
if (getCurrentMode() === MODE_REACT_API) {
fetch(url, {
method: method,
headers: FETCH_HEADER,
body: JSON.stringify(dataBody),
body: JSON.stringify(sanitizedBody),
})
.then((res) => {
if (res.ok) {
if (stepNum === 5) {
callbackFunc && callbackFunc();
return res;
}
return res.json();
const isJson = res.headers.get('content-type')?.includes('application/json');
return isJson ? res.json() : res;
}
requestErrorHandler(res.status);
throw res.status;
})
.then((data) => {
if (setFieldValueObj && method === 'POST') {
// update the field id after a successful post
switch (setFieldValueObj.fieldName) {
case 'organization':
setFieldValueObj.method(`${setFieldValueObj.fieldName}.id`, data[0]?.id);
setFieldValueObj.method('organization.address.id', data[0]?.address?.id);
updateFormValuesObj.theNewValue.organization.id = data[0]?.id;
updateFormValuesObj.theNewValue.organization.address.id = data[0]?.address?.id;
updateFormValuesObj.setUpdatedFormValues(updateFormValuesObj.theNewValue);
break;
case 'representative.member':
setFieldValueObj.method(`${setFieldValueObj.fieldName}.id`, data[0]?.id);
updateFormValuesObj.theNewValue.representative.member.id = data[0]?.id;
updateFormValuesObj.setUpdatedFormValues(updateFormValuesObj.theNewValue);
break;
case 'representative.marketing':
setFieldValueObj.method(`${setFieldValueObj.fieldName}.id`, data[0]?.id);
updateFormValuesObj.theNewValue.representative.marketing.id = data[0]?.id;
updateFormValuesObj.setUpdatedFormValues(updateFormValuesObj.theNewValue);
break;
case 'representative.accounting':
setFieldValueObj.method(`${setFieldValueObj.fieldName}.id`, data[0]?.id);
updateFormValuesObj.theNewValue.representative.accounting.id = data[0]?.id;
updateFormValuesObj.setUpdatedFormValues(updateFormValuesObj.theNewValue);
break;
case 'workingGroups':
setFieldValueObj.method(`workingGroups[${index}].id`, data[0]?.id);
setFieldValueObj.method(`workingGroups[${index}].workingGroupRepresentative.id`, data[0]?.contact?.id);
if (updateFormValuesObj?.theNewValue) {
updateFormValuesObj.theNewValue.workingGroups[index].id = data[0]?.id;
updateFormValuesObj.theNewValue.workingGroups[index].workingGroupRepresentative.id =
data[0]?.contact?.id;
updateFormValuesObj.setUpdatedFormValues(updateFormValuesObj.theNewValue);
}
break;
case 'signingAuthorityRepresentative':
setFieldValueObj.method.signingAuthority(`${setFieldValueObj.fieldName}.id`, data[0]?.id);
setFieldValueObj.method.companyInfo(`${setFieldValueObj.fieldName}.id`, data[0]?.id);
updateFormValuesObj.theNewValue.signingAuthorityRepresentative.id = data[0]?.id;
updateFormValuesObj.setUpdatedFormValues(updateFormValuesObj.theNewValue);
break;
default:
break;
}
}
onSuccess && onSuccess(data);
})
.catch((err) => {
console.log(err);
// This will make sure when "then" is skipped, we could still handle the error
// And because this "err" is just an error message without error/status code, so we use 0 here.
requestErrorHandler(err);
});
}
......
......@@ -85,3 +85,5 @@ export const showErrMsg = (
break;
}
};
export const isIE = () => navigator.userAgent.indexOf('MSIE') > -1 || navigator.userAgent.indexOf('Trident') > -1;
......@@ -4,6 +4,7 @@ import { useFormik } from 'formik';
import SignIn from './SignIn/SignIn';
import {
application_api_prefix,
CONTACT_TYPE,
END_POINT,
FETCH_HEADER,
getCurrentMode,
......@@ -28,7 +29,15 @@ import Step from '../UIComponents/Steppers/Step';
import SignInIntroduction from './SignIn/SignInIntroduction';
import SubmitSuccess from './SubmitSuccess/SubmitSuccess';
import { VALIDATION_SCHEMA_FOR_ENROLMENT_FORM } from '../UIComponents/FormComponents/ValidationSchema';
import { checkValidityWithoutSubmitting, executeSendDataByStep, isProd } from '../../Utils/formFunctionHelpers';
import {
fetchWrapperForm,
checkValidityWithoutSubmitting,
isProd,
matchCompanyFieldsToBackend,
matchContactFieldsToBackend,
matchMembershipLevelFieldsToBackend,
matchWGFieldsToBackend,
} from '../../Utils/formFunctionHelpers';
import MembershipContext from '../../Context/MembershipContext';
import TopSlideMsg from '../UIComponents/Notifications/TopSlideMsg';
......@@ -44,76 +53,139 @@ export default function Application() {
const [workingGroupsUserJoined, setWorkingGroupsUserJoined] = useState([]);
const submitCompanyInfo = () => {
const values = formik.values;
setUpdatedFormValues(values);
const { values, setFieldValue } = formik;
!isProd && console.log('updated company info: ', values);
const setFieldValueObj = {
fieldName: {
organization: 'organization',
member: 'representative.member',
accounting: 'representative.accounting',
marketing: 'representative.marketing',
},
method: formik.setFieldValue,
const onSuccessOrg = (data) => {
// Add id to local data after a successful POST
if (values.organization.address.id) {
return;
}
setFieldValue('organization.address.id', data.address?.id || data[0]?.address?.id || '');
};
fetchWrapperForm(
currentFormId,
END_POINT.organizations,
matchCompanyFieldsToBackend(values.organization, currentFormId),
onSuccessOrg
);
const onSuccessMemberRep = (data) => {
// Add id to local data after a successful POST
if (values.representative.member.id) {
return;
}
setFieldValue('representative.member.id', data.id || data[0]?.id || '');
};
fetchWrapperForm(
currentFormId,
END_POINT.contacts,
matchContactFieldsToBackend(values.representative.member, CONTACT_TYPE.COMPANY, currentFormId),
onSuccessMemberRep
);
const onSuccessMarketingRep = (data) => {
if (values.representative.marketing.id) {
return;
}
setFieldValue('representative.marketing.id', data.id || data[0]?.id || '');
};
fetchWrapperForm(
currentFormId,
END_POINT.contacts,
matchContactFieldsToBackend(values.representative.marketing, CONTACT_TYPE.MARKETING, currentFormId),
onSuccessMarketingRep
);
const updateFormValuesObj = {
theNewValue: values,
setUpdatedFormValues,
const onSuccessAccountingRep = (data) => {
if (values.representative.accounting.id) {
return;
}
setFieldValue('representative.accounting.id', data.id || data[0]?.id || '');
};
fetchWrapperForm(
currentFormId,
END_POINT.contacts,
matchContactFieldsToBackend(values.representative.accounting, CONTACT_TYPE.ACCOUNTING, currentFormId),
onSuccessAccountingRep
);
executeSendDataByStep(1, values, currentFormId, currentUserForm.name, setFieldValueObj, updateFormValuesObj);
// Only make the API call when signingAuthorityRepresentative has an id
fetchWrapperForm(
currentFormId,
'',
matchMembershipLevelFieldsToBackend(values, currentFormId, currentUserForm.name)
);
let isWGRepSameAsCompany = false;
values.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
isWGRepSameAsCompany &&
values.workingGroups.forEach((item) => {
fetchWrapperForm(currentFormId, END_POINT.working_groups, matchWGFieldsToBackend(item, currentFormId));
});
// Only make the API call when signingAuthority Representative has an id and sameAsCompany is true
// If not, it means there is nothing in the db, so no need to update.
values.signingAuthorityRepresentative.id &&
executeSendDataByStep(4, values, currentFormId, currentUserForm.name, setFieldValueObj, updateFormValuesObj);
if (values.signingAuthorityRepresentative.id && values.signingAuthorityRepresentative.sameAsCompany) {
fetchWrapperForm(
currentFormId,
END_POINT.contacts,
matchContactFieldsToBackend(values.signingAuthorityRepresentative, CONTACT_TYPE.SIGNING, currentFormId)
);
}
};
const submitMembershipLevel = () => {
const values = formik.values;
setUpdatedFormValues(values);
const { values } = formik;
!isProd && console.log('updated membership level: ', values);
executeSendDataByStep(2, values, currentFormId, currentUserForm.name);
fetchWrapperForm(
currentFormId,
'',
matchMembershipLevelFieldsToBackend(values, currentFormId, currentUserForm.name)
);
};
const submitWorkingGroups = () => {
const values = formik.values;
setUpdatedFormValues(values);
const { values, setFieldValue } = formik;
!isProd && console.log('updated working groups: ', values);
if (!values.skipJoiningWG) {
// If the user is joining at least 1 wg, then make related API call
const setFieldValueObj = {
fieldName: 'workingGroups',
method: formik.setFieldValue,
const onSuccessWG = (data, item, index) => {
if (item.id) {
return;
}
const newWGArray = values.workingGroups.map((wg, i) =>
i === index ? { ...wg, id: data.id || data[0]?.id || '' } : wg
);
setFieldValue('workingGroups', newWGArray);
};
executeSendDataByStep(3, values, currentFormId, currentUserForm.name, setFieldValueObj, {
theNewValue: values,
setUpdatedFormValues,
values.workingGroups.forEach((item, index) => {
fetchWrapperForm(currentFormId, END_POINT.working_groups, matchWGFieldsToBackend(item, currentFormId), (data) =>
onSuccessWG(data, item, index)
);
});
}
};
const submitSigningAuthority = () => {
const values = formik.values;
setUpdatedFormValues(values);
const { values, setFieldValue } = formik;
!isProd && console.log('updated SigningAuthority: ', values);
const setFieldValueObj = {
fieldName: 'signingAuthorityRepresentative',
method: {
signingAuthority: formik.setFieldValue,