From 58cde5d5eefc226ea2bb2935f6e7008fd08d4633 Mon Sep 17 00:00:00 2001 From: Juliana Kang Date: Tue, 20 Feb 2024 12:25:01 -0500 Subject: [PATCH] feat: Use country-state-city to populate state dropdown in StateProvinceFormInput (#849) REV-3842 --- package-lock.json | 6 + package.json | 1 + .../payment-form/StateProvinceFormInput.jsx | 4 +- .../payment-form/StripePaymentForm.test.jsx | 25 +++- .../payment-form/utils/countryStatesMap.js | 115 ------------------ .../payment-form/utils/form-validators.js | 20 ++- 6 files changed, 49 insertions(+), 122 deletions(-) delete mode 100644 src/payment/checkout/payment-form/utils/countryStatesMap.js diff --git a/package-lock.json b/package-lock.json index 4d1027de5..dd436b84e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "bootstrap": "4.6.1", "classnames": "^2.3.1", "core-js": "^3.23.5", + "country-state-city": "^3.2.1", "form-urlencoded": "^6.0.6", "lodash.camelcase": "^4.3.0", "lodash.snakecase": "^4.1.1", @@ -7358,6 +7359,11 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/country-state-city": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/country-state-city/-/country-state-city-3.2.1.tgz", + "integrity": "sha512-kxbanqMc6izjhc/EHkGPCTabSPZ2G6eG4/97akAYHJUN4stzzFEvQPZoF8oXDQ+10gM/O/yUmISCR1ZVxyb6EA==" + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", diff --git a/package.json b/package.json index 8bb334f0c..1acc3a48d 100755 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "bootstrap": "4.6.1", "classnames": "^2.3.1", "core-js": "^3.23.5", + "country-state-city": "^3.2.1", "form-urlencoded": "^6.0.6", "lodash.camelcase": "^4.3.0", "lodash.snakecase": "^4.1.1", diff --git a/src/payment/checkout/payment-form/StateProvinceFormInput.jsx b/src/payment/checkout/payment-form/StateProvinceFormInput.jsx index 8252dc1dc..63565053f 100644 --- a/src/payment/checkout/payment-form/StateProvinceFormInput.jsx +++ b/src/payment/checkout/payment-form/StateProvinceFormInput.jsx @@ -3,16 +3,16 @@ import PropTypes from 'prop-types'; import { Field } from 'redux-form'; import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n'; +import { getCountryStatesMap } from './utils/form-validators'; import FormInput from './FormInput'; import FormSelect from './FormSelect'; -import getStates from './utils/countryStatesMap'; import messages from './StateProvinceFormInput.messages'; class StateProvinceFormInput extends React.Component { getOptions() { const options = []; const { country } = this.props; - const states = getStates(country); + const states = getCountryStatesMap(country); if (states) { options.push([( diff --git a/src/payment/checkout/payment-form/StripePaymentForm.test.jsx b/src/payment/checkout/payment-form/StripePaymentForm.test.jsx index c39fed99e..937faf803 100644 --- a/src/payment/checkout/payment-form/StripePaymentForm.test.jsx +++ b/src/payment/checkout/payment-form/StripePaymentForm.test.jsx @@ -128,8 +128,27 @@ describe('', () => { lastName: '', address: '', city: '', - country: 'GB', + country: 'AQ', // Antarctica does not have states, postal code not required + optionalField: '', + }, + { + firstName: '', + lastName: '', + address: '', + city: '', + country: 'GB', // United Kingdom has states, state becomes required, postal code is required postalCode: '', + state: '', + optionalField: '', + }, + { + firstName: '', + lastName: '', + address: '', + city: '', + country: 'CA', // Canada state and postal code are required + postalCode: '', + state: '', optionalField: '', }, { @@ -137,7 +156,7 @@ describe('', () => { lastName: '', address: '', city: '', - country: 'US', + country: 'US', // United States state and postal code are required postalCode: '', state: '', optionalField: '', @@ -147,7 +166,7 @@ describe('', () => { lastName: '', address: '', city: '', - country: 'IN', + country: 'IN', // India state is required state: '', optionalField: '', }, diff --git a/src/payment/checkout/payment-form/utils/countryStatesMap.js b/src/payment/checkout/payment-form/utils/countryStatesMap.js deleted file mode 100644 index 339ef782a..000000000 --- a/src/payment/checkout/payment-form/utils/countryStatesMap.js +++ /dev/null @@ -1,115 +0,0 @@ -const COUNTRY_STATES_MAP = { - CA: { - AB: 'Alberta', - BC: 'British Columbia', - MB: 'Manitoba', - NB: 'New Brunswick', - NL: 'Newfoundland and Labrador', - NS: 'Nova Scotia', - NT: 'Northwest Territories', - NU: 'Nunavut', - ON: 'Ontario', - PE: 'Prince Edward Island', - QC: 'Québec', - SK: 'Saskatchewan', - YT: 'Yukon', - }, - IN: { - AN: 'Andaman and Nicobar Islands', - AP: 'Andhra Pradesh', - AR: 'Arunachal Pradesh', - AS: 'Assam', - BR: 'Bihar', - CH: 'Chandigarh', - CT: 'Chhattisgarh', - DN: 'Dadra and Nagar Haveli', - DD: 'Daman and Diu', - DL: 'Delhi', - GA: 'Goa', - GJ: 'Gujarat', - HR: 'Haryana', - HP: 'Himachal Pradesh', - JK: 'Jammu and Kashmir', - JH: 'Jharkhand', - KA: 'Karnataka', - KL: 'Kerala', - LD: 'Lakshadweep', - MP: 'Madhya Pradesh', - MH: 'Maharashtra', - MN: 'Manipur', - ML: 'Meghalaya', - MZ: 'Mizoram', - NL: 'Nagaland', - OR: 'Odisha', - PY: 'Puducherry', - PB: 'Punjab', - RJ: 'Rajasthan', - SK: 'Sikkim', - TN: 'Tamil Nadu', - TG: 'Telangana', - TR: 'Tripura', - UP: 'Uttar Pradesh', - UT: 'Uttarakhand', - WB: 'West Bengal', - }, - US: { - AL: 'Alabama', - AK: 'Alaska', - AZ: 'Arizona', - AR: 'Arkansas', - AA: 'Armed Forces Americas', - AE: 'Armed Forces Europe', - AP: 'Armed Forces Pacific', - CA: 'California', - CO: 'Colorado', - CT: 'Connecticut', - DE: 'Delaware', - DC: 'District Of Columbia', - FL: 'Florida', - GA: 'Georgia', - HI: 'Hawaii', - ID: 'Idaho', - IL: 'Illinois', - IN: 'Indiana', - IA: 'Iowa', - KS: 'Kansas', - KY: 'Kentucky', - LA: 'Louisiana', - ME: 'Maine', - MD: 'Maryland', - MA: 'Massachusetts', - MI: 'Michigan', - MN: 'Minnesota', - MS: 'Mississippi', - MO: 'Missouri', - MT: 'Montana', - NE: 'Nebraska', - NV: 'Nevada', - NH: 'New Hampshire', - NJ: 'New Jersey', - NM: 'New Mexico', - NY: 'New York', - NC: 'North Carolina', - ND: 'North Dakota', - OH: 'Ohio', - OK: 'Oklahoma', - OR: 'Oregon', - PA: 'Pennsylvania', - RI: 'Rhode Island', - SC: 'South Carolina', - SD: 'South Dakota', - TN: 'Tennessee', - TX: 'Texas', - UT: 'Utah', - VT: 'Vermont', - VA: 'Virginia', - WA: 'Washington', - WV: 'West Virginia', - WI: 'Wisconsin', - WY: 'Wyoming', - }, -}; - -export default function getStates(country) { - return country && COUNTRY_STATES_MAP[country.toUpperCase()]; -} diff --git a/src/payment/checkout/payment-form/utils/form-validators.js b/src/payment/checkout/payment-form/utils/form-validators.js index 249a15266..5e2bc208f 100644 --- a/src/payment/checkout/payment-form/utils/form-validators.js +++ b/src/payment/checkout/payment-form/utils/form-validators.js @@ -1,4 +1,18 @@ -import getStates from './countryStatesMap'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { State } from 'country-state-city'; + +export const getCountryStatesMap = (country) => { + const states = State.getStatesOfCountry(country); + + if (!states.length) { + return null; + } + const statesMap = {}; + states.forEach((state) => { + statesMap[state.isoCode] = state.name; + }); + return country && statesMap; +}; // eslint-disable-next-line import/prefer-default-export export function isPostalCodeRequired(selectedCountry) { @@ -39,7 +53,9 @@ export function getRequiredFields(fieldValues, isBulkOrder = false, enableStripe requiredFields.postalCode = postalCode; } - if (getStates(country)) { + // By using the country-state-city library to populate states, every country that + // has states from the ISO 3166-2 list will have states as a required field + if (getCountryStatesMap(country)) { requiredFields.state = state; }