From 5b0d57b8658fc651c217536ad5b676646d240059 Mon Sep 17 00:00:00 2001 From: Yu Long Date: Mon, 11 Dec 2023 16:07:30 +0100 Subject: [PATCH 1/5] feat: use expiresAt time for the QR payments if presented --- packages/lib/src/components/WeChat/WeChat.ts | 25 ++++++++++++++++--- .../utils/getTimeDiffInMinutesFromNow.test.ts | 21 ++++++++++++++++ .../src/utils/getTimeDiffInMinutesFromNow.ts | 15 +++++++++++ 3 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 packages/lib/src/utils/getTimeDiffInMinutesFromNow.test.ts create mode 100644 packages/lib/src/utils/getTimeDiffInMinutesFromNow.ts diff --git a/packages/lib/src/components/WeChat/WeChat.ts b/packages/lib/src/components/WeChat/WeChat.ts index 8b96717381..bfb97239cd 100644 --- a/packages/lib/src/components/WeChat/WeChat.ts +++ b/packages/lib/src/components/WeChat/WeChat.ts @@ -1,5 +1,7 @@ import QRLoaderContainer from '../helpers/QRLoaderContainer'; -import { delay, countdownTime } from './config'; +import { delay, countdownTime as defaultCountdownTime } from './config'; +import Instructions from '../PayMe/Instructions'; +import { getTimeDiffInMinutesFromNow } from '../../utils/getTimeDiffInMinutesFromNow'; class WeChatPayElement extends QRLoaderContainer { public static type = 'wechatpayQR'; @@ -7,10 +9,27 @@ class WeChatPayElement extends QRLoaderContainer { formatProps(props) { return { delay, - countdownTime, - ...super.formatProps(props) + redirectIntroduction: 'payme.openPayMeApp', + introduction: 'payme.scanQrCode', + timeToPay: 'payme.timeToPay', + buttonLabel: 'payme.redirectButtonLabel', + instructions: Instructions, + ...super.formatProps(props), + countdownTime: this.getCountDownTime(props) }; } + + getCountDownTime(props): number { + try { + const { expiresAt, delay } = props; + if (expiresAt) { + return getTimeDiffInMinutesFromNow(expiresAt, delay); + } + } catch (e) { + console.error(e); + return props.countdownTime ?? defaultCountdownTime; + } + } } export default WeChatPayElement; diff --git a/packages/lib/src/utils/getTimeDiffInMinutesFromNow.test.ts b/packages/lib/src/utils/getTimeDiffInMinutesFromNow.test.ts new file mode 100644 index 0000000000..d4e7cabc32 --- /dev/null +++ b/packages/lib/src/utils/getTimeDiffInMinutesFromNow.test.ts @@ -0,0 +1,21 @@ +import { getTimeDiffInMinutesFromNow } from './getTimeDiffInMinutesFromNow'; + +describe('getTimeDiffInMinutesFromNow', () => { + test('should return the time difference in minutes without delay', () => { + const fiveMinutes = 5; + const delay = 1000 * 60 * fiveMinutes; + const futureTime = new Date(Date.now() + delay); + expect(getTimeDiffInMinutesFromNow(futureTime.toISOString())).toEqual(fiveMinutes); + }); + + test('should return the time difference in minutes with delay', () => { + const fiveMinutes = 5; + const delay = 1000 * 60 * fiveMinutes; + const futureTime = new Date(Date.now() + delay); + expect(getTimeDiffInMinutesFromNow(futureTime.toISOString(), delay)).toEqual(0); + }); + + test('should throw an error when the time duration cannot be calculated', () => { + expect(() => getTimeDiffInMinutesFromNow('wrong datetime')).toThrow(); + }); +}); diff --git a/packages/lib/src/utils/getTimeDiffInMinutesFromNow.ts b/packages/lib/src/utils/getTimeDiffInMinutesFromNow.ts new file mode 100644 index 0000000000..2a115c684f --- /dev/null +++ b/packages/lib/src/utils/getTimeDiffInMinutesFromNow.ts @@ -0,0 +1,15 @@ +/** + * Calculate the time difference in minutes, between the future time and the current time (plus delay). + * @param futureTime - string in utc datetime format + * @param delayFromNow - milliseconds delay from now + */ +export function getTimeDiffInMinutesFromNow(futureTime: string, delayFromNow = 0) { + const future = new Date(futureTime); + const localDate = new Date(); + localDate.setTime(localDate.getTime() + delayFromNow); + const diff = (future.getTime() - localDate.getTime()) / 60000; + if (Number.isNaN(diff) || diff < 0) { + throw new Error('Invalid countdown duration. A default one will be used.'); + } + return diff; +} From 3602e1452d03a72e58f17587062eba655322ac68 Mon Sep 17 00:00:00 2001 From: Yu Long Date: Wed, 10 Jan 2024 11:34:13 +0100 Subject: [PATCH 2/5] test: add some tests --- .../src/components/BcmcMobile/BcmcMobile.ts | 6 ++-- .../lib/src/components/DuitNow/DuitNow.ts | 6 +--- packages/lib/src/components/PayMe/PayMe.ts | 6 ++-- packages/lib/src/components/PayNow/PayNow.ts | 6 +--- .../lib/src/components/PromptPay/PromptPay.ts | 6 +--- packages/lib/src/components/Swish/Swish.ts | 7 ++-- .../lib/src/components/WeChat/WeChat.test.ts | 31 +++++++++++++++- packages/lib/src/components/WeChat/WeChat.ts | 35 +++++-------------- packages/lib/src/components/WeChat/config.ts | 2 +- .../components/helpers/QRLoaderContainer.tsx | 28 +++++++++++++-- .../src/utils/getTimeDiffInMinutesFromNow.ts | 6 ++-- 11 files changed, 82 insertions(+), 57 deletions(-) diff --git a/packages/lib/src/components/BcmcMobile/BcmcMobile.ts b/packages/lib/src/components/BcmcMobile/BcmcMobile.ts index 82d484c3c1..c003570d3e 100644 --- a/packages/lib/src/components/BcmcMobile/BcmcMobile.ts +++ b/packages/lib/src/components/BcmcMobile/BcmcMobile.ts @@ -7,12 +7,12 @@ class BCMCMobileElement extends QRLoaderContainer { formatProps(props) { const isMobile = window.matchMedia('(max-width: 768px)').matches && /Android|iPhone|iPod/.test(navigator.userAgent); - return { + return super.formatProps({ delay: STATUS_INTERVAL, countdownTime: COUNTDOWN_MINUTES, buttonLabel: isMobile ? 'openApp' : 'generateQRCode', - ...super.formatProps(props) - }; + ...props + }); } } diff --git a/packages/lib/src/components/DuitNow/DuitNow.ts b/packages/lib/src/components/DuitNow/DuitNow.ts index dde01f8393..6c4e02ce7a 100644 --- a/packages/lib/src/components/DuitNow/DuitNow.ts +++ b/packages/lib/src/components/DuitNow/DuitNow.ts @@ -5,11 +5,7 @@ class DuitNowElement extends QRLoaderContainer { public static type = 'duitnow'; formatProps(props) { - return { - delay, - countdownTime, - ...super.formatProps(props) - }; + return super.formatProps({ delay, countdownTime, ...props }); } } diff --git a/packages/lib/src/components/PayMe/PayMe.ts b/packages/lib/src/components/PayMe/PayMe.ts index f98a434008..ff64b117a0 100644 --- a/packages/lib/src/components/PayMe/PayMe.ts +++ b/packages/lib/src/components/PayMe/PayMe.ts @@ -7,7 +7,7 @@ class PayMeElement extends QRLoaderContainer { private static defaultDelay = 2000; // ms formatProps(props) { - return { + return super.formatProps({ delay: PayMeElement.defaultDelay, countdownTime: PayMeElement.defaultCountdown, redirectIntroduction: 'payme.openPayMeApp', @@ -15,8 +15,8 @@ class PayMeElement extends QRLoaderContainer { timeToPay: 'payme.timeToPay', buttonLabel: 'payme.redirectButtonLabel', instructions: Instructions, - ...super.formatProps(props) - }; + ...props + }); } } diff --git a/packages/lib/src/components/PayNow/PayNow.ts b/packages/lib/src/components/PayNow/PayNow.ts index ca5be22436..375160e455 100644 --- a/packages/lib/src/components/PayNow/PayNow.ts +++ b/packages/lib/src/components/PayNow/PayNow.ts @@ -5,11 +5,7 @@ class PayNowElement extends QRLoaderContainer { public static type = 'paynow'; formatProps(props) { - return { - delay, - countdownTime, - ...super.formatProps(props) - }; + return super.formatProps({ delay, countdownTime, ...props }); } } diff --git a/packages/lib/src/components/PromptPay/PromptPay.ts b/packages/lib/src/components/PromptPay/PromptPay.ts index 9acc7b43e1..9961d0d32c 100644 --- a/packages/lib/src/components/PromptPay/PromptPay.ts +++ b/packages/lib/src/components/PromptPay/PromptPay.ts @@ -5,11 +5,7 @@ class PromptPayElement extends QRLoaderContainer { public static type = 'promptpay'; formatProps(props) { - return { - delay, - countdownTime, - ...super.formatProps(props) - }; + return super.formatProps({ delay, countdownTime, ...props }); } } diff --git a/packages/lib/src/components/Swish/Swish.ts b/packages/lib/src/components/Swish/Swish.ts index c6e1750180..bc9afed99a 100644 --- a/packages/lib/src/components/Swish/Swish.ts +++ b/packages/lib/src/components/Swish/Swish.ts @@ -2,13 +2,14 @@ import QRLoaderContainer from '../helpers/QRLoaderContainer'; class SwishElement extends QRLoaderContainer { public static type = 'swish'; + formatProps(props) { - return { + return super.formatProps({ delay: 2000, // ms countdownTime: 3, // min instructions: 'swish.pendingMessage', - ...super.formatProps(props) - }; + ...props + }); } } diff --git a/packages/lib/src/components/WeChat/WeChat.test.ts b/packages/lib/src/components/WeChat/WeChat.test.ts index db8fbef0b3..4ee17d9dd2 100644 --- a/packages/lib/src/components/WeChat/WeChat.test.ts +++ b/packages/lib/src/components/WeChat/WeChat.test.ts @@ -1,7 +1,25 @@ import WeChat from './WeChat'; +import * as utils from '../../utils/getTimeDiffInMinutesFromNow'; +import { countdownTime } from './config'; + +const calculateTimeDiffMock = jest.spyOn(utils, 'getTimeDiffInMinutesFromNow').mockImplementation(() => 5); describe('WeChat', () => { - describe('formatProps', () => {}); + describe('formatProps', () => { + test('should calculate the time difference if expiresAt exists', () => { + const expiresAt = '2024-01-15T14:00:48.321283089Z'; + const wechat = new WeChat({ expiresAt }); + expect(calculateTimeDiffMock).toHaveBeenCalledWith(expiresAt, wechat.props.delay); + }); + test('should use the countdownTime from the props if it exists', () => { + const wechat = new WeChat({ countdownTime: 3 }); + expect(wechat.props.countdownTime).toBe(3); + }); + test('should use the default countdownTime if neither expiresAt nor countdownTime value exists', () => { + const wechat = new WeChat({}); + expect(wechat.props.countdownTime).toBe(countdownTime); + }); + }); describe('isValid', () => { test('should be always true', () => { @@ -23,4 +41,15 @@ describe('WeChat', () => { expect(wechat.render()).toBe(null); }); }); + + describe('formatProps', () => { + describe('countdownTime', () => { + test('should calculate the time difference if expiresAt is provided', () => {}); + test('should return the default countdown time if expiresAt is not provided', () => {}); + test('should return the default countdown time if there are errors calculating the time difference', () => {}); + }); + describe('other props', () => { + test('should return the correct values for other props', () => {}); + }); + }); }); diff --git a/packages/lib/src/components/WeChat/WeChat.ts b/packages/lib/src/components/WeChat/WeChat.ts index bfb97239cd..ad2b44282a 100644 --- a/packages/lib/src/components/WeChat/WeChat.ts +++ b/packages/lib/src/components/WeChat/WeChat.ts @@ -1,35 +1,18 @@ import QRLoaderContainer from '../helpers/QRLoaderContainer'; -import { delay, countdownTime as defaultCountdownTime } from './config'; -import Instructions from '../PayMe/Instructions'; -import { getTimeDiffInMinutesFromNow } from '../../utils/getTimeDiffInMinutesFromNow'; +import { delay, countdownTime } from './config'; class WeChatPayElement extends QRLoaderContainer { public static type = 'wechatpayQR'; - formatProps(props) { - return { - delay, - redirectIntroduction: 'payme.openPayMeApp', - introduction: 'payme.scanQrCode', - timeToPay: 'payme.timeToPay', - buttonLabel: 'payme.redirectButtonLabel', - instructions: Instructions, - ...super.formatProps(props), - countdownTime: this.getCountDownTime(props) - }; - } + public static defaultProps = { + countdownTime, + delay, + ...QRLoaderContainer.defaultProps + }; - getCountDownTime(props): number { - try { - const { expiresAt, delay } = props; - if (expiresAt) { - return getTimeDiffInMinutesFromNow(expiresAt, delay); - } - } catch (e) { - console.error(e); - return props.countdownTime ?? defaultCountdownTime; - } - } + /* formatProps(props) { + return super.formatProps({ delay, countdownTime, ...props }); + }*/ } export default WeChatPayElement; diff --git a/packages/lib/src/components/WeChat/config.ts b/packages/lib/src/components/WeChat/config.ts index 13eb1569ab..13c5c806ef 100644 --- a/packages/lib/src/components/WeChat/config.ts +++ b/packages/lib/src/components/WeChat/config.ts @@ -1,4 +1,4 @@ -export const countdownTime = 15; // min +export const countdownTime = 8; // min export const delay = 2000; // ms export default { diff --git a/packages/lib/src/components/helpers/QRLoaderContainer.tsx b/packages/lib/src/components/helpers/QRLoaderContainer.tsx index c9b3fb1b8c..8ce4954b86 100644 --- a/packages/lib/src/components/helpers/QRLoaderContainer.tsx +++ b/packages/lib/src/components/helpers/QRLoaderContainer.tsx @@ -5,10 +5,11 @@ import QRLoader from '../internal/QRLoader'; import CoreProvider from '../../core/Context/CoreProvider'; import RedirectButton from '../internal/RedirectButton'; import SRPanelProvider from '../../core/Errors/SRPanelProvider'; +import { getTimeDiffInMinutesFromNow } from '../../utils/getTimeDiffInMinutesFromNow'; export interface QRLoaderContainerProps extends UIElementProps { /** - * Number of miliseconds that the component will wait in between status calls + * Number of milliseconds that the component will wait in between status calls */ delay?: number; @@ -17,12 +18,19 @@ export interface QRLoaderContainerProps extends UIElementProps { */ countdownTime?: number; + /** + * UTC timestamp from the /payments response. + * If it presents we should calculate the countdown time between the expiresAt and the current local time. + * Otherwise, it falls back to the merchant's countdownTime prop or the default one per QR payment. + */ + expiresAt?: string; + type?: string; brandLogo?: string; buttonLabel?: string; qrCodeImage?: string; paymentData?: string; - introduction: string; + introduction?: string; redirectIntroduction?: string; timeToPay?: string; instructions?: string | (() => h.JSX.Element); @@ -40,6 +48,22 @@ class QRLoaderContainer {} }; + formatProps(props) { + return { + ...props, + countdownTime: this.getCountDownTime(props) + }; + } + + getCountDownTime({ expiresAt, delay, countdownTime }): number { + try { + return expiresAt ? getTimeDiffInMinutesFromNow(expiresAt, delay) : countdownTime; + } catch (e) { + console.warn(e?.message); + return countdownTime; + } + } + formatData() { return { paymentMethod: { diff --git a/packages/lib/src/utils/getTimeDiffInMinutesFromNow.ts b/packages/lib/src/utils/getTimeDiffInMinutesFromNow.ts index 2a115c684f..302f40529f 100644 --- a/packages/lib/src/utils/getTimeDiffInMinutesFromNow.ts +++ b/packages/lib/src/utils/getTimeDiffInMinutesFromNow.ts @@ -5,9 +5,9 @@ */ export function getTimeDiffInMinutesFromNow(futureTime: string, delayFromNow = 0) { const future = new Date(futureTime); - const localDate = new Date(); - localDate.setTime(localDate.getTime() + delayFromNow); - const diff = (future.getTime() - localDate.getTime()) / 60000; + const now = new Date(); + now.setTime(now.getTime() + delayFromNow); + const diff = (future.getTime() - now.getTime()) / 60000; if (Number.isNaN(diff) || diff < 0) { throw new Error('Invalid countdown duration. A default one will be used.'); } From b47e7d23ffa122bad79d4818acb37147f047c887 Mon Sep 17 00:00:00 2001 From: Yu Long Date: Tue, 16 Jan 2024 16:06:48 +0100 Subject: [PATCH 3/5] refactor: change all QR payments to calculate countdown time based on the expiresAt --- .../src/components/BcmcMobile/BcmcMobile.ts | 17 ++++++------- .../lib/src/components/DuitNow/DuitNow.ts | 8 ++++--- packages/lib/src/components/PayMe/PayMe.ts | 24 +++++++++---------- packages/lib/src/components/PayNow/PayNow.ts | 8 ++++--- .../lib/src/components/PromptPay/PromptPay.ts | 8 ++++--- packages/lib/src/components/Swish/Swish.ts | 14 +++++------ packages/lib/src/components/WeChat/WeChat.ts | 6 +---- .../utils/getTimeDiffInMinutesFromNow.test.ts | 5 ++-- .../src/utils/getTimeDiffInMinutesFromNow.ts | 4 ++-- 9 files changed, 44 insertions(+), 50 deletions(-) diff --git a/packages/lib/src/components/BcmcMobile/BcmcMobile.ts b/packages/lib/src/components/BcmcMobile/BcmcMobile.ts index c003570d3e..ad326958c2 100644 --- a/packages/lib/src/components/BcmcMobile/BcmcMobile.ts +++ b/packages/lib/src/components/BcmcMobile/BcmcMobile.ts @@ -3,17 +3,14 @@ import { STATUS_INTERVAL, COUNTDOWN_MINUTES } from './config'; class BCMCMobileElement extends QRLoaderContainer { public static type = 'bcmc_mobile'; + private static isMobile = window.matchMedia('(max-width: 768px)').matches && /Android|iPhone|iPod/.test(navigator.userAgent); - formatProps(props) { - const isMobile = window.matchMedia('(max-width: 768px)').matches && /Android|iPhone|iPod/.test(navigator.userAgent); - - return super.formatProps({ - delay: STATUS_INTERVAL, - countdownTime: COUNTDOWN_MINUTES, - buttonLabel: isMobile ? 'openApp' : 'generateQRCode', - ...props - }); - } + protected static defaultProps = { + delay: STATUS_INTERVAL, + countdownTime: COUNTDOWN_MINUTES, + buttonLabel: BCMCMobileElement.isMobile ? 'openApp' : 'generateQRCode', + ...QRLoaderContainer.defaultProps + }; } export default BCMCMobileElement; diff --git a/packages/lib/src/components/DuitNow/DuitNow.ts b/packages/lib/src/components/DuitNow/DuitNow.ts index 6c4e02ce7a..9608cf4598 100644 --- a/packages/lib/src/components/DuitNow/DuitNow.ts +++ b/packages/lib/src/components/DuitNow/DuitNow.ts @@ -4,9 +4,11 @@ import { delay, countdownTime } from './config'; class DuitNowElement extends QRLoaderContainer { public static type = 'duitnow'; - formatProps(props) { - return super.formatProps({ delay, countdownTime, ...props }); - } + protected static defaultProps = { + countdownTime, + delay, + ...QRLoaderContainer.defaultProps + }; } export default DuitNowElement; diff --git a/packages/lib/src/components/PayMe/PayMe.ts b/packages/lib/src/components/PayMe/PayMe.ts index ff64b117a0..3fb3d1cc7d 100644 --- a/packages/lib/src/components/PayMe/PayMe.ts +++ b/packages/lib/src/components/PayMe/PayMe.ts @@ -3,21 +3,19 @@ import Instructions from './Instructions'; class PayMeElement extends QRLoaderContainer { public static type = 'payme'; - private static defaultCountdown = 10; // min + private static defaultCountdown = 30; // min private static defaultDelay = 2000; // ms - formatProps(props) { - return super.formatProps({ - delay: PayMeElement.defaultDelay, - countdownTime: PayMeElement.defaultCountdown, - redirectIntroduction: 'payme.openPayMeApp', - introduction: 'payme.scanQrCode', - timeToPay: 'payme.timeToPay', - buttonLabel: 'payme.redirectButtonLabel', - instructions: Instructions, - ...props - }); - } + protected static defaultProps = { + delay: PayMeElement.defaultDelay, + countdownTime: PayMeElement.defaultCountdown, + redirectIntroduction: 'payme.openPayMeApp', + introduction: 'payme.scanQrCode', + timeToPay: 'payme.timeToPay', + buttonLabel: 'payme.redirectButtonLabel', + instructions: Instructions, + ...QRLoaderContainer.defaultProps + }; } export default PayMeElement; diff --git a/packages/lib/src/components/PayNow/PayNow.ts b/packages/lib/src/components/PayNow/PayNow.ts index 375160e455..f092daae74 100644 --- a/packages/lib/src/components/PayNow/PayNow.ts +++ b/packages/lib/src/components/PayNow/PayNow.ts @@ -4,9 +4,11 @@ import { delay, countdownTime } from './config'; class PayNowElement extends QRLoaderContainer { public static type = 'paynow'; - formatProps(props) { - return super.formatProps({ delay, countdownTime, ...props }); - } + protected static defaultProps = { + countdownTime, + delay, + ...QRLoaderContainer.defaultProps + }; } export default PayNowElement; diff --git a/packages/lib/src/components/PromptPay/PromptPay.ts b/packages/lib/src/components/PromptPay/PromptPay.ts index 9961d0d32c..c12e8e313a 100644 --- a/packages/lib/src/components/PromptPay/PromptPay.ts +++ b/packages/lib/src/components/PromptPay/PromptPay.ts @@ -4,9 +4,11 @@ import { delay, countdownTime } from './config'; class PromptPayElement extends QRLoaderContainer { public static type = 'promptpay'; - formatProps(props) { - return super.formatProps({ delay, countdownTime, ...props }); - } + protected static defaultProps = { + countdownTime, + delay, + ...QRLoaderContainer.defaultProps + }; } export default PromptPayElement; diff --git a/packages/lib/src/components/Swish/Swish.ts b/packages/lib/src/components/Swish/Swish.ts index bc9afed99a..40394682d3 100644 --- a/packages/lib/src/components/Swish/Swish.ts +++ b/packages/lib/src/components/Swish/Swish.ts @@ -3,14 +3,12 @@ import QRLoaderContainer from '../helpers/QRLoaderContainer'; class SwishElement extends QRLoaderContainer { public static type = 'swish'; - formatProps(props) { - return super.formatProps({ - delay: 2000, // ms - countdownTime: 3, // min - instructions: 'swish.pendingMessage', - ...props - }); - } + protected static defaultProps = { + delay: 2000, // ms + countdownTime: 3, // min + instructions: 'swish.pendingMessage', + ...QRLoaderContainer.defaultProps + }; } export default SwishElement; diff --git a/packages/lib/src/components/WeChat/WeChat.ts b/packages/lib/src/components/WeChat/WeChat.ts index ad2b44282a..4679abb4be 100644 --- a/packages/lib/src/components/WeChat/WeChat.ts +++ b/packages/lib/src/components/WeChat/WeChat.ts @@ -4,15 +4,11 @@ import { delay, countdownTime } from './config'; class WeChatPayElement extends QRLoaderContainer { public static type = 'wechatpayQR'; - public static defaultProps = { + protected static defaultProps = { countdownTime, delay, ...QRLoaderContainer.defaultProps }; - - /* formatProps(props) { - return super.formatProps({ delay, countdownTime, ...props }); - }*/ } export default WeChatPayElement; diff --git a/packages/lib/src/utils/getTimeDiffInMinutesFromNow.test.ts b/packages/lib/src/utils/getTimeDiffInMinutesFromNow.test.ts index d4e7cabc32..0177434a58 100644 --- a/packages/lib/src/utils/getTimeDiffInMinutesFromNow.test.ts +++ b/packages/lib/src/utils/getTimeDiffInMinutesFromNow.test.ts @@ -3,12 +3,11 @@ import { getTimeDiffInMinutesFromNow } from './getTimeDiffInMinutesFromNow'; describe('getTimeDiffInMinutesFromNow', () => { test('should return the time difference in minutes without delay', () => { const fiveMinutes = 5; - const delay = 1000 * 60 * fiveMinutes; - const futureTime = new Date(Date.now() + delay); + const futureTime = new Date(Date.now() + 1000 * 60 * fiveMinutes); expect(getTimeDiffInMinutesFromNow(futureTime.toISOString())).toEqual(fiveMinutes); }); - test('should return the time difference in minutes with delay', () => { + test('should return the time difference in minutes with a delay', () => { const fiveMinutes = 5; const delay = 1000 * 60 * fiveMinutes; const futureTime = new Date(Date.now() + delay); diff --git a/packages/lib/src/utils/getTimeDiffInMinutesFromNow.ts b/packages/lib/src/utils/getTimeDiffInMinutesFromNow.ts index 302f40529f..c553d45194 100644 --- a/packages/lib/src/utils/getTimeDiffInMinutesFromNow.ts +++ b/packages/lib/src/utils/getTimeDiffInMinutesFromNow.ts @@ -1,6 +1,6 @@ /** - * Calculate the time difference in minutes, between the future time and the current time (plus delay). - * @param futureTime - string in utc datetime format + * Calculate the time difference in minutes, between the future UTC time and the current time (plus delay). + * @param futureTime - UTC date time string in the ISO 8601 format * @param delayFromNow - milliseconds delay from now */ export function getTimeDiffInMinutesFromNow(futureTime: string, delayFromNow = 0) { From 3bbe2214018771b00941c67b4ab51a00c6ecfb36 Mon Sep 17 00:00:00 2001 From: Yu Long Date: Tue, 16 Jan 2024 16:19:12 +0100 Subject: [PATCH 4/5] chore: add changeset --- .changeset/slimy-pillows-wash.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .changeset/slimy-pillows-wash.md diff --git a/.changeset/slimy-pillows-wash.md b/.changeset/slimy-pillows-wash.md new file mode 100644 index 0000000000..aeed8636c2 --- /dev/null +++ b/.changeset/slimy-pillows-wash.md @@ -0,0 +1,8 @@ +--- +"@adyen/adyen-web": minor +--- + +For the following QR based payments - `bcmc_mobile`, `duitnow`, `payme`, `paynow`, `pix`, `promptpay`, `swish` and `wechatpayQR`, we improved how we calculate the countdown time. + +Specifically, we calculate the QR countdown time based on the `expiresAt` timestamp from the `/payments` response if it is returned in the action object, otherwise we use merchant's frontend configuration. +If both are not presented, we fall back to the default value. \ No newline at end of file From 957d5077fad670a40256008abc164d914900eb9a Mon Sep 17 00:00:00 2001 From: Yu Long Date: Tue, 16 Jan 2024 16:32:50 +0100 Subject: [PATCH 5/5] refactor: rollback some changes which are for the testing --- packages/lib/src/components/PayMe/PayMe.ts | 2 +- packages/lib/src/components/WeChat/WeChat.test.ts | 11 ----------- packages/lib/src/components/WeChat/config.ts | 2 +- 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/packages/lib/src/components/PayMe/PayMe.ts b/packages/lib/src/components/PayMe/PayMe.ts index 3fb3d1cc7d..5b70769801 100644 --- a/packages/lib/src/components/PayMe/PayMe.ts +++ b/packages/lib/src/components/PayMe/PayMe.ts @@ -3,7 +3,7 @@ import Instructions from './Instructions'; class PayMeElement extends QRLoaderContainer { public static type = 'payme'; - private static defaultCountdown = 30; // min + private static defaultCountdown = 10; // min private static defaultDelay = 2000; // ms protected static defaultProps = { diff --git a/packages/lib/src/components/WeChat/WeChat.test.ts b/packages/lib/src/components/WeChat/WeChat.test.ts index 4ee17d9dd2..af78391a34 100644 --- a/packages/lib/src/components/WeChat/WeChat.test.ts +++ b/packages/lib/src/components/WeChat/WeChat.test.ts @@ -41,15 +41,4 @@ describe('WeChat', () => { expect(wechat.render()).toBe(null); }); }); - - describe('formatProps', () => { - describe('countdownTime', () => { - test('should calculate the time difference if expiresAt is provided', () => {}); - test('should return the default countdown time if expiresAt is not provided', () => {}); - test('should return the default countdown time if there are errors calculating the time difference', () => {}); - }); - describe('other props', () => { - test('should return the correct values for other props', () => {}); - }); - }); }); diff --git a/packages/lib/src/components/WeChat/config.ts b/packages/lib/src/components/WeChat/config.ts index 13c5c806ef..13eb1569ab 100644 --- a/packages/lib/src/components/WeChat/config.ts +++ b/packages/lib/src/components/WeChat/config.ts @@ -1,4 +1,4 @@ -export const countdownTime = 8; // min +export const countdownTime = 15; // min export const delay = 2000; // ms export default {