From d6491ea8a55fc29629c4cb9834ceaa7f4154a4fd Mon Sep 17 00:00:00 2001 From: Szymon Mysiak Date: Tue, 19 May 2026 17:53:22 +0200 Subject: [PATCH 1/5] fix --- src/apm/API.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/apm/API.ts b/src/apm/API.ts index 64dbedb..5d047a9 100644 --- a/src/apm/API.ts +++ b/src/apm/API.ts @@ -511,8 +511,12 @@ module ProcessOut { } } - // Return on first PENDING response OR anytime there are elements - const shouldReturn = !internalOptions.hasReturnedFirstPending || apiResponse.elements; + // Return on first PENDING response OR when there are non-empty elements. + // Empty/absent elements on subsequent polls (e.g. gateway awaiting webhook) must NOT + // trigger a re-render — that would unmount the Pending view, wipe instructions/QR, + // and reset the countdown timer (see Pending.ts componentWillUnmount). + const hasElements = !!(apiResponse.elements && apiResponse.elements.length > 0); + const shouldReturn = !internalOptions.hasReturnedFirstPending || hasElements; if (shouldReturn) { if (!internalOptions.hasReturnedFirstPending) { From 9f93919477e2d718eca2b5314fce9ba4bdc525c0 Mon Sep 17 00:00:00 2001 From: Szymon Mysiak Date: Tue, 19 May 2026 18:20:38 +0200 Subject: [PATCH 2/5] fix --- src/apm/Page.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/apm/Page.ts b/src/apm/Page.ts index 0fc6b1c..1322755 100644 --- a/src/apm/Page.ts +++ b/src/apm/Page.ts @@ -55,6 +55,7 @@ module ProcessOut { (request.bind(APIImpl) as APIRequest)({ hasConfirmedPending, onSuccess: ({ elements, ...config }) => { + const previousState = this.state this.state = config.state callback && callback(null, this.state); @@ -73,7 +74,15 @@ module ProcessOut { } if (config.state === 'PENDING') { - ContextImpl.context.page.render(APMViewPending, { elements, config }) + // Only render on the transition INTO PENDING. Background polling responses + // (PENDING → PENDING) must not re-render — that would unmount the Pending view, + // wiping displayed instructions/QR codes and resetting the countdown timer (see + // Pending.ts componentWillUnmount removing pending.startTime). When the user + // confirms via "I have sent the payment", the existing view's startTimer drives + // its own setState to reflect the confirmed state, so no re-render is needed here. + if (previousState !== 'PENDING') { + ContextImpl.context.page.render(APMViewPending, { elements, config }) + } } }, onError: ({ elements, ...config }) => { From 2f888ba0d6d1c53cfb8d9b21e89a7cb67148869c Mon Sep 17 00:00:00 2001 From: Szymon Mysiak Date: Tue, 19 May 2026 18:40:59 +0200 Subject: [PATCH 3/5] fix --- src/apm/API.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/apm/API.ts b/src/apm/API.ts index 5d047a9..64dbedb 100644 --- a/src/apm/API.ts +++ b/src/apm/API.ts @@ -511,12 +511,8 @@ module ProcessOut { } } - // Return on first PENDING response OR when there are non-empty elements. - // Empty/absent elements on subsequent polls (e.g. gateway awaiting webhook) must NOT - // trigger a re-render — that would unmount the Pending view, wipe instructions/QR, - // and reset the countdown timer (see Pending.ts componentWillUnmount). - const hasElements = !!(apiResponse.elements && apiResponse.elements.length > 0); - const shouldReturn = !internalOptions.hasReturnedFirstPending || hasElements; + // Return on first PENDING response OR anytime there are elements + const shouldReturn = !internalOptions.hasReturnedFirstPending || apiResponse.elements; if (shouldReturn) { if (!internalOptions.hasReturnedFirstPending) { From 63766b10eef9ef22d6f8e1608001f0a77ab21e58 Mon Sep 17 00:00:00 2001 From: Szymon Mysiak Date: Tue, 19 May 2026 18:42:57 +0200 Subject: [PATCH 4/5] fix --- src/apm/Page.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/apm/Page.ts b/src/apm/Page.ts index 1322755..f8615a2 100644 --- a/src/apm/Page.ts +++ b/src/apm/Page.ts @@ -77,9 +77,7 @@ module ProcessOut { // Only render on the transition INTO PENDING. Background polling responses // (PENDING → PENDING) must not re-render — that would unmount the Pending view, // wiping displayed instructions/QR codes and resetting the countdown timer (see - // Pending.ts componentWillUnmount removing pending.startTime). When the user - // confirms via "I have sent the payment", the existing view's startTimer drives - // its own setState to reflect the confirmed state, so no re-render is needed here. + // Pending.ts componentWillUnmount removing pending.startTime). if (previousState !== 'PENDING') { ContextImpl.context.page.render(APMViewPending, { elements, config }) } From 1644371f147c1fdf8797ca0509d8b19c53504873 Mon Sep 17 00:00:00 2001 From: Szymon Mysiak Date: Wed, 20 May 2026 17:54:05 +0200 Subject: [PATCH 5/5] chore: bump version to 1.9.4 Co-Authored-By: Claude Opus 4.7 (1M context) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a4a8b86..ae75442 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "processout.js", - "version": "1.9.3", + "version": "1.9.4", "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",