From a78fcf2f12e36f914dd4b2d83350565bf560673b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Pa=C5=BAdziurek?= Date: Fri, 28 Nov 2025 13:01:15 +0100 Subject: [PATCH 1/3] fix(apm): rename phone "value" to "number" to conform with the BE API contracts --- src/apm/elements/phone.ts | 66 ++++++++++++++++++------------------- src/apm/views/utils/form.ts | 10 +++--- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/apm/elements/phone.ts b/src/apm/elements/phone.ts index 13125ee6..2eff929c 100644 --- a/src/apm/elements/phone.ts +++ b/src/apm/elements/phone.ts @@ -8,7 +8,7 @@ module ProcessOut { name: string, }> oninput?: FormFieldUpdate, - onblur?: (key: string, value: { dialing_code: string, value: string }) => void, + onblur?: (key: string, value: { dialing_code: string, number: string }) => void, value?: { dialing_code: string, value: string }, } @@ -46,7 +46,7 @@ module ProcessOut { const parseCleanNumber = (currentValue: string, dialingCode: string, iso: string) => { const phoneUtil = (window as any).libphonenumber.PhoneNumberUtil.getInstance(); - + try { // Try to parse as international number first const parsedNumber = phoneUtil.parseAndKeepRawInput(currentValue, iso); @@ -61,16 +61,16 @@ module ProcessOut { // Use StateManager for internal state management const { state, setState } = useComponentState({ dialing_code: value && value.dialing_code || dialing_codes[0] && dialing_codes[0].value || '', - value: value && value.value || '', + number: value && value.value || '', iso: '' }); - + // Load libphonenumber and handle all state initialization in callback ContextImpl.context.page.loadScript('libphonenumber', 'https://cdnjs.cloudflare.com/ajax/libs/google-libphonenumber/3.2.42/libphonenumber.min.js', () => { let dialingCode = state.dialing_code || dialing_codes[0].value; - let phoneNumber = state.value || ''; + let phoneNumber = state.number || ''; let iso = state.iso; - + // Set ISO code using libphonenumber if (!iso) { const phoneUtil = (window as any).libphonenumber && (window as any).libphonenumber.PhoneNumberUtil && (window as any).libphonenumber.PhoneNumberUtil.getInstance(); @@ -88,7 +88,7 @@ module ProcessOut { iso = dialing_codes.find(item => item.value === state.dialing_code) && dialing_codes.find(item => item.value === state.dialing_code).region_code || ''; } } - + // Update the UI if elements are available if (phoneRef) { phoneRef.value = getFullNumber(dialingCode, phoneNumber); @@ -100,7 +100,7 @@ module ProcessOut { if (dialingCodesRef) { dialingCodesRef.value = iso; } - + // Trigger callback to update form state if there's a value if (value) { oninput && oninput(name, state, true); @@ -108,7 +108,7 @@ module ProcessOut { setState({ dialing_code: dialingCode, - value: phoneNumber, + number: phoneNumber, iso: iso }); }); @@ -130,7 +130,7 @@ module ProcessOut { const cursorPosition = input.selectionStart; let dialingCode = state.dialing_code; - let phoneNumber = state.value; + let phoneNumber = state.number; let iso = state.iso; // Helper function to update state and UI when country is detected @@ -138,39 +138,39 @@ module ProcessOut { dialingCode = detectedCountry.dialingCode.value; phoneNumber = nationalNumber; iso = detectedCountry.region; - + // Update the input with formatted value const formattedValue = getFullNumber(dialingCode, phoneNumber); input.value = formattedValue; - + // Update flag image const flagImg = input.parentElement.querySelector('img'); if (flagImg) { flagImg.src = `https://flagcdn.com/w80/${iso.toLowerCase()}.jpg`; flagImg.alt = `Selected ${detectedCountry.dialingCode.name} dialing code`; } - + // Update select value if (dialingCodesRef) { dialingCodesRef.value = iso; } - + if (label) { updateFilledState(input); } - + // Trigger callback oninput && oninput(name, { dialing_code: dialingCode, - value: phoneNumber, + number: phoneNumber, }); - + // Set cursor at end input.setSelectionRange(formattedValue.length, formattedValue.length); setState({ dialing_code: dialingCode, - value: phoneNumber, + number: phoneNumber, iso: iso }); }; @@ -187,12 +187,12 @@ module ProcessOut { const parsedNumber = phoneUtil.parseAndKeepRawInput(valueWithoutCurrentPrefix, ''); const countryCode = parsedNumber.getCountryCode(); const nationalNumber = parsedNumber.getNationalNumber().toString(); - + // Find matching dialing code in our list - const matchingDialingCode = dialing_codes.find(code => + const matchingDialingCode = dialing_codes.find(code => code.value === `+${countryCode}` ); - + if (matchingDialingCode) { const detectedCountry = { dialingCode: matchingDialingCode, @@ -219,7 +219,7 @@ module ProcessOut { // Use libphonenumber to properly parse the number const cleanNumber = parseCleanNumber(currentValue, dialingCode, iso); - + const formattedValue = getFullNumber(dialingCode, cleanNumber); let newCursorPosition = numberStartIndex; @@ -247,22 +247,22 @@ module ProcessOut { dialingCodesRef.showPicker() setState({ dialing_code: dialingCode, - value: phoneNumber, + number: phoneNumber, iso: iso }); return } - if (state.value !== cleanNumber) { + if (state.number !== cleanNumber) { phoneNumber = cleanNumber; oninput && oninput(name, { dialing_code: dialingCode, - value: phoneNumber, + number: phoneNumber, }); } setState({ dialing_code: dialingCode, - value: phoneNumber, + number: phoneNumber, iso: iso }); input.setSelectionRange(newCursorPosition, newCursorPosition); @@ -299,19 +299,19 @@ module ProcessOut { const handleSelectChange = e => { const currentValue = (e.target as HTMLSelectElement).value; - const cleanNumber = parseCleanNumber(getFullNumber(state.dialing_code, state.value), state.dialing_code, state.iso); + const cleanNumber = parseCleanNumber(getFullNumber(state.dialing_code, state.number), state.dialing_code, state.iso); const newDialingCode = dialing_codes.find(item => item.region_code === currentValue).value; - + setState({ dialing_code: newDialingCode, iso: currentValue, - value: cleanNumber + number: cleanNumber }); - + phoneRef.value = getFullNumber(newDialingCode, cleanNumber); phoneRef.focus(); - oninput && oninput(name, { dialing_code: newDialingCode, value: cleanNumber }); + oninput && oninput(name, { dialing_code: newDialingCode, number: cleanNumber }); (e.target as HTMLSelectElement).parentElement.querySelector('img').src = `https://flagcdn.com/w80/${currentValue.toLowerCase()}.jpg`; } @@ -349,7 +349,7 @@ module ProcessOut { const handleMouseDown = () => { focusMethod = 'mouse'; } - + if (!state.dialing_code) { return null } @@ -382,7 +382,7 @@ module ProcessOut { input({ type: "tel", autocomplete: "tel", - value: getFullNumber(state.dialing_code, state.value), + value: getFullNumber(state.dialing_code, state.number), inputMode: "tel", name: `${name}.value`, disabled, diff --git a/src/apm/views/utils/form.ts b/src/apm/views/utils/form.ts index 8642032a..ad2ddb38 100644 --- a/src/apm/views/utils/form.ts +++ b/src/apm/views/utils/form.ts @@ -1,7 +1,7 @@ module ProcessOut { interface PhoneState { dialing_code: string - value: string + number: string } export interface FormState { touched: Record @@ -61,7 +61,7 @@ module ProcessOut { } let errors = { ...prevState.form.errors } - + if (prevState.form.touched[key]) { delete errors[key] errors[key] = validateField(prevState, key, value) @@ -169,7 +169,7 @@ module ProcessOut { } else { otpType = "text"; } - + input = OTP({ name: field.key, label: field.label, @@ -192,7 +192,7 @@ module ProcessOut { onblur: onBlur(setState), errored: !!error, disabled: state.loading, - value: value as PhoneState, + number: value as PhoneState, }); break; } @@ -264,7 +264,7 @@ module ProcessOut { className: 'group-boolean' } } - + // Don't group other field types for now return null } From 30e228b21f98d9f5da49e1f3d22b78a7b9f575e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Pa=C5=BAdziurek?= Date: Fri, 28 Nov 2025 13:55:49 +0100 Subject: [PATCH 2/3] v1.6.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ceedf066..116d812a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "processout.js", - "version": "1.6.2", + "version": "1.6.3", "description": "ProcessOut.js is a JavaScript library for ProcessOut's payment processing API.", "scripts": { "build:processout": "tsc -p src/processout && uglifyjs --compress --keep-fnames --ie8 dist/processout.js -o dist/processout.js", From 03d4caa9e0a61432de35f4f3fed8b190a0573d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Pa=C5=BAdziurek?= Date: Fri, 28 Nov 2025 15:26:12 +0100 Subject: [PATCH 3/3] refactor: add custom config support for examples/apm testing --- .gitignore | 3 ++ examples/apm/config-example.json | 21 ++++++++++++++ examples/apm/index.html | 49 +++++++++++++++++++++++++------- 3 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 examples/apm/config-example.json diff --git a/.gitignore b/.gitignore index b9537d88..c39ae3f0 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,6 @@ node_modules # Dist files dist + +# APM test config files +examples/apm/config.json diff --git a/examples/apm/config-example.json b/examples/apm/config-example.json new file mode 100644 index 00000000..8519e7d1 --- /dev/null +++ b/examples/apm/config-example.json @@ -0,0 +1,21 @@ +{ + "project_id": "test-proj_IPW8DgC6yoI2YEUGmmkHERjbuMiGKBdx", + "gateways": [ + { + "value": "gway_conf_vupnl08h7hy1jxf3cz5z4dc2lw5py2ve", + "name": "ProcessOut" + }, + { + "value": "gway_conf_fh67c2llxupjhcqxxbr4cvlfosncdbr7:authorization", + "name": "Forage Authorization" + }, + { + "value": "gway_conf_fh67c2llxupjhcqxxbr4cvlfosncdbr7:tokenization", + "name": "Forage Tokenization" + }, + { + "value": "gway_conf_zuo5iyryn390he7fx3rd50twwvhpcvob.adyenblik", + "name": "Adyen Blik" + } + ] +} diff --git a/examples/apm/index.html b/examples/apm/index.html index 96b19e33..7a28b49e 100644 --- a/examples/apm/index.html +++ b/examples/apm/index.html @@ -8,11 +8,9 @@
+ @@ -23,10 +21,31 @@