Skip to content

Commit da68676

Browse files
fix(apm): rename phone "value" to "number" to conform with the BE API contracts (#225)
## Description We're sending phone number as "value" field instead of "number" and BE ignores it. As a result, we end up sending empty phone number to the PSP. ## Solution Rename "value" field to "number" to conform with the BE API contracts.
1 parent ede230c commit da68676

6 files changed

Lines changed: 102 additions & 49 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,6 @@ node_modules
3232

3333
# Dist files
3434
dist
35+
36+
# APM test config files
37+
examples/apm/config.json

examples/apm/config-example.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"project_id": "test-proj_IPW8DgC6yoI2YEUGmmkHERjbuMiGKBdx",
3+
"gateways": [
4+
{
5+
"value": "gway_conf_vupnl08h7hy1jxf3cz5z4dc2lw5py2ve",
6+
"name": "ProcessOut"
7+
},
8+
{
9+
"value": "gway_conf_fh67c2llxupjhcqxxbr4cvlfosncdbr7:authorization",
10+
"name": "Forage Authorization"
11+
},
12+
{
13+
"value": "gway_conf_fh67c2llxupjhcqxxbr4cvlfosncdbr7:tokenization",
14+
"name": "Forage Tokenization"
15+
},
16+
{
17+
"value": "gway_conf_zuo5iyryn390he7fx3rd50twwvhpcvob.adyenblik",
18+
"name": "Adyen Blik"
19+
}
20+
]
21+
}

examples/apm/index.html

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@
88
<body>
99
<div>
1010
<form id="initialise-apm">
11+
<input type="text" id="project-id" name="project_id" placeholder="Project ID" />
1112
<select name="gateway" id="apm-gateway">
12-
<option value="gway_conf_vupnl08h7hy1jxf3cz5z4dc2lw5py2ve">ProcessOut</option>
13-
<option value="gway_conf_fh67c2llxupjhcqxxbr4cvlfosncdbr7:authorization">Forage Authorization</option>
14-
<option value="gway_conf_fh67c2llxupjhcqxxbr4cvlfosncdbr7:tokenization">Forage Tokenization</option>
15-
<option value="gway_conf_zuo5iyryn390he7fx3rd50twwvhpcvob.adyenblik">Adyen Blik</option>
13+
<option value="">Select Gateway</option>
1614
</select>
1715
<input type="text" id="invoice-id" name="invoice_id" placeholder="Invoice ID" />
1816
<input type="text" id="customer-id" name="customer_id" placeholder="Customer ID" style="display: none" />
@@ -23,10 +21,31 @@
2321
<div id="apm-container"></div>
2422
<script src="../../dist/processout.js" crossorigin="anonymous"></script>
2523
<script>
26-
document.addEventListener("DOMContentLoaded", function () {
27-
const projectId = 'test-proj_IPW8DgC6yoI2YEUGmmkHERjbuMiGKBdx';
24+
function populateGatewaySelect(gateways) {
25+
const select = document.getElementById('apm-gateway');
26+
gateways
27+
.sort((a, b) => a.name.localeCompare(b.name))
28+
.forEach(gateway => {
29+
const option = document.createElement('option');
30+
option.value = gateway.value;
31+
option.textContent = gateway.name;
32+
select.appendChild(option);
33+
});
34+
}
35+
36+
function initConfigs(file) {
37+
return fetch(file)
38+
.then(response => response.json())
39+
.then(data => {
40+
document.getElementById('project-id').value = data.project_id;
41+
populateGatewaySelect(data.gateways);
42+
})
43+
}
44+
45+
function initProcessOut() {
46+
const projectId = document.getElementById('project-id').value;
2847
const gatewayEl = document.querySelector('#apm-gateway');
29-
48+
3049
// Build gateway dictionary from select options
3150
const gatewayDict = {};
3251

@@ -49,7 +68,7 @@
4968
gatewayEl.addEventListener('change', (e) => {
5069
const value = e.target.value;
5170
const gateway = gatewayDict[value];
52-
71+
5372
switch (gateway) {
5473
case 'Forage Authorization':
5574
flow = 'authorization';
@@ -141,11 +160,11 @@
141160
if (apm) {
142161
apm.on('*', ({ type, ...rest }) => {
143162
console.log(Date.now(), `apm event - ${type}`, rest)
144-
if (type === 'success' || type === 'failure' || type === 'payment-cancelled') {
163+
if (type === 'success' || type === 'failure' || type === 'payment-cancelled') {
145164
apm.cleanUp()
146165
}
147166
})
148-
167+
149168
try {
150169
apm.initialise()
151170
} catch (e) {
@@ -154,6 +173,16 @@
154173
}
155174
}
156175
})
176+
}
177+
178+
179+
document.addEventListener("DOMContentLoaded", function () {
180+
initConfigs('config.json')
181+
.catch(error => {
182+
console.error('Error loading gateways:', error);
183+
return initConfigs('config-example.json');
184+
})
185+
.then(it => initProcessOut());
157186
})
158187
</script>
159188
</body>

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "processout.js",
3-
"version": "1.6.2",
3+
"version": "1.6.3",
44
"description": "ProcessOut.js is a JavaScript library for ProcessOut's payment processing API.",
55
"scripts": {
66
"build:processout": "tsc -p src/processout && uglifyjs --compress --keep-fnames --ie8 dist/processout.js -o dist/processout.js",

src/apm/elements/phone.ts

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module ProcessOut {
88
name: string,
99
}>
1010
oninput?: FormFieldUpdate,
11-
onblur?: (key: string, value: { dialing_code: string, value: string }) => void,
11+
onblur?: (key: string, value: { dialing_code: string, number: string }) => void,
1212
value?: { dialing_code: string, value: string },
1313
}
1414

@@ -46,7 +46,7 @@ module ProcessOut {
4646

4747
const parseCleanNumber = (currentValue: string, dialingCode: string, iso: string) => {
4848
const phoneUtil = (window as any).libphonenumber.PhoneNumberUtil.getInstance();
49-
49+
5050
try {
5151
// Try to parse as international number first
5252
const parsedNumber = phoneUtil.parseAndKeepRawInput(currentValue, iso);
@@ -61,16 +61,16 @@ module ProcessOut {
6161
// Use StateManager for internal state management
6262
const { state, setState } = useComponentState({
6363
dialing_code: value && value.dialing_code || dialing_codes[0] && dialing_codes[0].value || '',
64-
value: value && value.value || '',
64+
number: value && value.value || '',
6565
iso: ''
6666
});
67-
67+
6868
// Load libphonenumber and handle all state initialization in callback
6969
ContextImpl.context.page.loadScript('libphonenumber', 'https://cdnjs.cloudflare.com/ajax/libs/google-libphonenumber/3.2.42/libphonenumber.min.js', () => {
7070
let dialingCode = state.dialing_code || dialing_codes[0].value;
71-
let phoneNumber = state.value || '';
71+
let phoneNumber = state.number || '';
7272
let iso = state.iso;
73-
73+
7474
// Set ISO code using libphonenumber
7575
if (!iso) {
7676
const phoneUtil = (window as any).libphonenumber && (window as any).libphonenumber.PhoneNumberUtil && (window as any).libphonenumber.PhoneNumberUtil.getInstance();
@@ -88,7 +88,7 @@ module ProcessOut {
8888
iso = dialing_codes.find(item => item.value === state.dialing_code) && dialing_codes.find(item => item.value === state.dialing_code).region_code || '';
8989
}
9090
}
91-
91+
9292
// Update the UI if elements are available
9393
if (phoneRef) {
9494
phoneRef.value = getFullNumber(dialingCode, phoneNumber);
@@ -100,15 +100,15 @@ module ProcessOut {
100100
if (dialingCodesRef) {
101101
dialingCodesRef.value = iso;
102102
}
103-
103+
104104
// Trigger callback to update form state if there's a value
105105
if (value) {
106106
oninput && oninput(name, state, true);
107107
}
108108

109109
setState({
110110
dialing_code: dialingCode,
111-
value: phoneNumber,
111+
number: phoneNumber,
112112
iso: iso
113113
});
114114
});
@@ -130,47 +130,47 @@ module ProcessOut {
130130
const cursorPosition = input.selectionStart;
131131

132132
let dialingCode = state.dialing_code;
133-
let phoneNumber = state.value;
133+
let phoneNumber = state.number;
134134
let iso = state.iso;
135135

136136
// Helper function to update state and UI when country is detected
137137
const updateDetectedCountry = (detectedCountry, nationalNumber: string) => {
138138
dialingCode = detectedCountry.dialingCode.value;
139139
phoneNumber = nationalNumber;
140140
iso = detectedCountry.region;
141-
141+
142142
// Update the input with formatted value
143143
const formattedValue = getFullNumber(dialingCode, phoneNumber);
144144
input.value = formattedValue;
145-
145+
146146
// Update flag image
147147
const flagImg = input.parentElement.querySelector('img');
148148
if (flagImg) {
149149
flagImg.src = `https://flagcdn.com/w80/${iso.toLowerCase()}.jpg`;
150150
flagImg.alt = `Selected ${detectedCountry.dialingCode.name} dialing code`;
151151
}
152-
152+
153153
// Update select value
154154
if (dialingCodesRef) {
155155
dialingCodesRef.value = iso;
156156
}
157-
157+
158158
if (label) {
159159
updateFilledState(input);
160160
}
161-
161+
162162
// Trigger callback
163163
oninput && oninput(name, {
164164
dialing_code: dialingCode,
165-
value: phoneNumber,
165+
number: phoneNumber,
166166
});
167-
167+
168168
// Set cursor at end
169169
input.setSelectionRange(formattedValue.length, formattedValue.length);
170170

171171
setState({
172172
dialing_code: dialingCode,
173-
value: phoneNumber,
173+
number: phoneNumber,
174174
iso: iso
175175
});
176176
};
@@ -187,12 +187,12 @@ module ProcessOut {
187187
const parsedNumber = phoneUtil.parseAndKeepRawInput(valueWithoutCurrentPrefix, '');
188188
const countryCode = parsedNumber.getCountryCode();
189189
const nationalNumber = parsedNumber.getNationalNumber().toString();
190-
190+
191191
// Find matching dialing code in our list
192-
const matchingDialingCode = dialing_codes.find(code =>
192+
const matchingDialingCode = dialing_codes.find(code =>
193193
code.value === `+${countryCode}`
194194
);
195-
195+
196196
if (matchingDialingCode) {
197197
const detectedCountry = {
198198
dialingCode: matchingDialingCode,
@@ -219,7 +219,7 @@ module ProcessOut {
219219

220220
// Use libphonenumber to properly parse the number
221221
const cleanNumber = parseCleanNumber(currentValue, dialingCode, iso);
222-
222+
223223
const formattedValue = getFullNumber(dialingCode, cleanNumber);
224224

225225
let newCursorPosition = numberStartIndex;
@@ -247,22 +247,22 @@ module ProcessOut {
247247
dialingCodesRef.showPicker()
248248
setState({
249249
dialing_code: dialingCode,
250-
value: phoneNumber,
250+
number: phoneNumber,
251251
iso: iso
252252
});
253253
return
254254
}
255255

256-
if (state.value !== cleanNumber) {
256+
if (state.number !== cleanNumber) {
257257
phoneNumber = cleanNumber;
258258
oninput && oninput(name, {
259259
dialing_code: dialingCode,
260-
value: phoneNumber,
260+
number: phoneNumber,
261261
});
262262
}
263263
setState({
264264
dialing_code: dialingCode,
265-
value: phoneNumber,
265+
number: phoneNumber,
266266
iso: iso
267267
});
268268
input.setSelectionRange(newCursorPosition, newCursorPosition);
@@ -299,19 +299,19 @@ module ProcessOut {
299299

300300
const handleSelectChange = e => {
301301
const currentValue = (e.target as HTMLSelectElement).value;
302-
const cleanNumber = parseCleanNumber(getFullNumber(state.dialing_code, state.value), state.dialing_code, state.iso);
302+
const cleanNumber = parseCleanNumber(getFullNumber(state.dialing_code, state.number), state.dialing_code, state.iso);
303303

304304
const newDialingCode = dialing_codes.find(item => item.region_code === currentValue).value;
305-
305+
306306
setState({
307307
dialing_code: newDialingCode,
308308
iso: currentValue,
309-
value: cleanNumber
309+
number: cleanNumber
310310
});
311-
311+
312312
phoneRef.value = getFullNumber(newDialingCode, cleanNumber);
313313
phoneRef.focus();
314-
oninput && oninput(name, { dialing_code: newDialingCode, value: cleanNumber });
314+
oninput && oninput(name, { dialing_code: newDialingCode, number: cleanNumber });
315315

316316
(e.target as HTMLSelectElement).parentElement.querySelector('img').src = `https://flagcdn.com/w80/${currentValue.toLowerCase()}.jpg`;
317317
}
@@ -349,7 +349,7 @@ module ProcessOut {
349349
const handleMouseDown = () => {
350350
focusMethod = 'mouse';
351351
}
352-
352+
353353
if (!state.dialing_code) {
354354
return null
355355
}
@@ -382,7 +382,7 @@ module ProcessOut {
382382
input({
383383
type: "tel",
384384
autocomplete: "tel",
385-
value: getFullNumber(state.dialing_code, state.value),
385+
value: getFullNumber(state.dialing_code, state.number),
386386
inputMode: "tel",
387387
name: `${name}.value`,
388388
disabled,

src/apm/views/utils/form.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module ProcessOut {
22
interface PhoneState {
33
dialing_code: string
4-
value: string
4+
number: string
55
}
66
export interface FormState {
77
touched: Record<string, boolean>
@@ -61,7 +61,7 @@ module ProcessOut {
6161
}
6262

6363
let errors = { ...prevState.form.errors }
64-
64+
6565
if (prevState.form.touched[key]) {
6666
delete errors[key]
6767
errors[key] = validateField(prevState, key, value)
@@ -169,7 +169,7 @@ module ProcessOut {
169169
} else {
170170
otpType = "text";
171171
}
172-
172+
173173
input = OTP({
174174
name: field.key,
175175
label: field.label,
@@ -192,7 +192,7 @@ module ProcessOut {
192192
onblur: onBlur(setState),
193193
errored: !!error,
194194
disabled: state.loading,
195-
value: value as PhoneState,
195+
number: value as PhoneState,
196196
});
197197
break;
198198
}
@@ -264,7 +264,7 @@ module ProcessOut {
264264
className: 'group-boolean'
265265
}
266266
}
267-
267+
268268
// Don't group other field types for now
269269
return null
270270
}

0 commit comments

Comments
 (0)