import { groupMigrationOrMember } from 'common/src/app/selectors/accountStateSelectors';
import { addressFields } from '../data/enum/FieldNames/AccountFieldNames';
import { getApiNoCache } from '../actions/externalApiActions';
import { POSTCODE_IO_VALIDATE } from '../data/externalApis';
import * as ValidateOn from '../enhanced-redux-form/data/ValidateOn';
import { countryCodeValue, countryCode } from '../data/enum/Countries';
import * as AddressFormats from '../data/AddressFormats';
import { POSTAL_CODES } from '../data/regexPatterns';
import CountryPostalCode from '../data/enum/CountryPostalCode';
import getCountry from '../util/getCountry';
const addressFieldsArray = [
addressFields.ADDRESS_LINE_1,
addressFields.CITY_OR_TOWN,
addressFields.STATE,
addressFields.ZIP_OR_POSTAL,
addressFields.COUNTY,
addressFields.COUNTRY,
];
// These are the only mandatory address field(s) for the group member
const requiredGroupAddressField = [addressFields.ZIP_OR_POSTAL];
/**
* Returns amended fieldnames
* @param {string} addressField | address fieldname
* @param {string} addressType | billing, shipping or null
*/
const formatAddressType = (addressField, addressType) =>
addressType ? `${addressType}.${addressField}` : addressField;
/**
* Returns rules for region specific field
* @param {string} region
* @param {string} fieldName
* @param {string} rule
*
*/
const getCountryFieldRules = (country, fieldName, rule) => {
const countryCodeString = countryCodeValue[country] || countryCode.DEFAULT;
// For IRELAND we need to do the validation for the COUNTY_IE field
const fieldNameValue =
country === countryCode.IRELAND && fieldName === addressFields.COUNTY
? addressFields.COUNTY_IE
: fieldName;
const currentRules = countryCodeString && AddressFormats[countryCodeString][fieldNameValue];
return currentRules && currentRules.find(fieldRule => fieldRule === rule);
};
/**
* Helper function to determine if the postcode is BFPO valid
*
* @param {string} postcode
*/
export const isBfpoPostcode = postcode => {
const postcodeUpper = postcode.toUpperCase();
return postcodeUpper.startsWith('BF1') || postcodeUpper.startsWith('BF2');
};
/**
* Helper function to determine if a UK postcode is valid, skips checks if
* postcode is a BFPO postcode
*
* @param {string} postcode
*/
export const isValidUkPostcode = postcode => async dispatch => {
if (!isBfpoPostcode(postcode)) {
return await dispatch(getApiNoCache(POSTCODE_IO_VALIDATE, postcode));
}
return true;
};
export const createIsValidUkPostcodeRule = async (value, values, fieldName, dispatch) => {
const addressType = fieldName.substring(0, fieldName.indexOf('.'));
// Only run validation when checking the postcode field
if (fieldName === formatAddressType(addressFields.ZIP_OR_POSTAL, addressType)) {
// if country selected is UK perform validation
const countryValue = addressType
? values?.[addressType]?.[addressFields.COUNTRY]
: values?.[addressFields.COUNTRY];
if (countryValue === countryCode.GB && value) {
return await dispatch(isValidUkPostcode(value));
}
return true;
}
return true;
};
/**
*
* @param {string} addressType | current validations address type
* Returns an object with validation fields filled for address type and region
*/
const address = (addressType = '', validateOn = [ValidateOn.BLUR]) =>
addressFieldsArray.reduce((obj, fieldName) => {
const fieldNameWithType = formatAddressType(fieldName, addressType);
let country = '';
// eslint-disable-next-line no-param-reassign
obj[fieldNameWithType] = {
validators: [
{
rule: async (value, values, fieldname, dispatch) =>
await createIsValidUkPostcodeRule(value, values, fieldNameWithType, dispatch),
message: {
locale: `validation.errors.${addressFields.ZIP_OR_POSTAL}.invalid`,
},
},
// Adds required validation to all fields
{
rule: (value, values, fieldname, dispatch) => {
country = getCountry(values, addressType);
return (dispatch(groupMigrationOrMember()) &&
requiredGroupAddressField.indexOf(fieldName) > -1) ||
(!dispatch(groupMigrationOrMember()) &&
getCountryFieldRules(getCountry(values, addressType), fieldName, 'required'))
? value || value === 0
: true;
},
message: {
locale: `validation.errors.${fieldName}.required`,
params: {
POSTAL_CODE: () => CountryPostalCode[countryCodeValue[country]] || 'Zipcode',
},
},
},
// Adds format validation to all fields
{
rule: (value, values) => {
country = getCountry(values, addressType);
return getCountryFieldRules(country, fieldName, 'postCode')
? POSTAL_CODES[country].test(value)
: true;
},
message: {
locale: `validation.errors.${fieldName}.formatError`,
params: {
POSTAL_CODE: () => CountryPostalCode[countryCodeValue[country]] || 'Zipcode',
},
},
},
],
validateOn,
};
return obj;
}, {});
export default address;