Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: PayMe wallet #2476

Merged
merged 11 commits into from
Jan 9, 2024
5 changes: 5 additions & 0 deletions .changeset/happy-crews-arrive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@adyen/adyen-web': minor
---

Add support for the PayMe payment method.
15 changes: 15 additions & 0 deletions packages/lib/src/components/PayMe/Instructions.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@import '../../style/index';

.adyen-checkout-payme-instructions {
font-size: $font-size-small;
text-align: center;
color: #5c687c;
line-height: 20px;

&__steps {
list-style-position: inside;
padding-inline-start: 0;
margin: 16px 0;
padding-bottom: 8px;
}
}
25 changes: 25 additions & 0 deletions packages/lib/src/components/PayMe/Instructions.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { render, screen } from '@testing-library/preact';
import { h } from 'preact';
import Language from '../../language';
import { Resources } from '../../core/Context/Resources';
import CoreProvider from '../../core/Context/CoreProvider';
import Instructions from './Instructions';

describe('Instructions', () => {
const customRender = (ui: h.JSX.Element) => {
return render(
// @ts-ignore ignore
<CoreProvider i18n={new Language()} loadingContext="test" resources={new Resources()}>
{ui}
</CoreProvider>
);
};

test('should see a list of instructions and footnote', async () => {
customRender(<Instructions />);
expect(await screen.findByText('Open the PayMe app', { exact: false })).toBeInTheDocument();
expect(await screen.findByText('Scan the QR code', { exact: false })).toBeInTheDocument();
expect(await screen.findByText('Complete the payment in the app', { exact: false })).toBeInTheDocument();
expect(await screen.findByText('Please do not close this page before the payment is completed', { exact: false })).toBeInTheDocument();
});
});
20 changes: 20 additions & 0 deletions packages/lib/src/components/PayMe/Instructions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import useCoreContext from '../../core/Context/useCoreContext';
import { h } from 'preact';
import './Instructions.scss';

export default function Instructions() {
const { i18n } = useCoreContext();
const steps = i18n.get('payme.instructions.steps');
const footnote = i18n.get('payme.instructions.footnote');

return (
<div className="adyen-checkout-payme-instructions">
<ol className="adyen-checkout-payme-instructions__steps">
{steps.split('%@').map((step, index) => (
<li key={`instruction-${index}`}>{step}</li>
))}
</ol>
<span>{footnote}</span>
</div>
);
}
23 changes: 23 additions & 0 deletions packages/lib/src/components/PayMe/PayMe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import QRLoaderContainer from '../helpers/QRLoaderContainer';
import Instructions from './Instructions';

class PayMeElement extends QRLoaderContainer {
public static type = 'payme';
private static defaultCountdown = 10; // min
private static defaultDelay = 2000; // ms

formatProps(props) {
return {
delay: PayMeElement.defaultDelay,
countdownTime: PayMeElement.defaultCountdown,
redirectIntroduction: 'payme.openPayMeApp',
introduction: 'payme.scanQrCode',
timeToPay: 'payme.timeToPay',
buttonLabel: 'payme.redirectButtonLabel',
instructions: Instructions,
...super.formatProps(props)
};
}
}

export default PayMeElement;
1 change: 1 addition & 0 deletions packages/lib/src/components/PayMe/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './PayMe';
4 changes: 3 additions & 1 deletion packages/lib/src/components/helpers/QRLoaderContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ export interface QRLoaderContainerProps extends UIElementProps {
qrCodeImage?: string;
paymentData?: string;
introduction: string;
instructions?: string;
redirectIntroduction?: string;
timeToPay?: string;
instructions?: string | (() => h.JSX.Element);
copyBtn?: boolean;
}

Expand Down
2 changes: 2 additions & 0 deletions packages/lib/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import PromptPay from './PromptPay';
import Duitnow from './DuitNow';
import ANCV from './ANCV';
import Trustly from './Trustly';
import PayMe from './PayMe';

/**
* Maps each component with a Component element.
Expand Down Expand Up @@ -210,6 +211,7 @@ const componentsMap = {
promptpay: PromptPay,
paynow: PayNow,
duitnow: Duitnow,
payme: PayMe,
/** QRLoader */

/** Await */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export class CountdownA11yReporter {

constructor(props: ICountdownA11yService) {
const { srPanel, i18n } = props;

this.srPanel = srPanel;
this.i18n = i18n;
// Force the srPanel to update ariaRelevant
Expand Down
18 changes: 13 additions & 5 deletions packages/lib/src/components/internal/QRLoader/QRLoader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ class QRLoader extends Component<QRLoaderProps, QRLoaderState> {
throttleTime: 60000,
classNameModifiers: [],
throttledInterval: 10000,
introduction: 'wechatpay.scanqrcode'
introduction: 'wechatpay.scanqrcode',
timeToPay: 'wechatpay.timetopay',
buttonLabel: 'openApp'
};

// Retry until getting a complete response from the server or it times out\
Expand Down Expand Up @@ -144,7 +146,6 @@ class QRLoader extends Component<QRLoaderProps, QRLoaderState> {
const { i18n, loadingContext } = useCoreContext();
const getImage = useImage();
const qrCodeImage = this.props.qrCodeData ? `${loadingContext}${QRCODE_URL}${this.props.qrCodeData}` : this.props.qrCodeImage;

const finalState = (image, message) => {
const status = i18n.get(message);
useA11yReporter(status);
Expand Down Expand Up @@ -177,7 +178,7 @@ class QRLoader extends Component<QRLoaderProps, QRLoaderState> {
);
}

const timeToPayString = i18n.get('wechatpay.timetopay').split('%@');
const timeToPayString = i18n.get(this.props.timeToPay).split('%@');

const qrSubtitleRef = useAutoFocus();

Expand All @@ -197,7 +198,10 @@ class QRLoader extends Component<QRLoaderProps, QRLoaderState> {

{url && (
<div className="adyen-checkout__qr-loader__app-link">
<Button classNameModifiers={['qr-loader']} onClick={() => this.redirectToApp(url)} label={i18n.get('openApp')} />
{this.props.redirectIntroduction && (
<div className="adyen-checkout__qr-loader__subtitle">{i18n.get(this.props.redirectIntroduction)}</div>
)}
<Button classNameModifiers={['qr-loader']} onClick={() => this.redirectToApp(url)} label={i18n.get(this.props.buttonLabel)} />
<ContentSeparator />
</div>
)}
Expand Down Expand Up @@ -225,7 +229,11 @@ class QRLoader extends Component<QRLoaderProps, QRLoaderState> {
&nbsp;{timeToPayString[1]}
</div>

{this.props.instructions && <div className="adyen-checkout__qr-loader__instructions">{i18n.get(this.props.instructions)}</div>}
{typeof this.props.instructions === 'string' ? (
<div className="adyen-checkout__qr-loader__instructions">{i18n.get(this.props.instructions)}</div>
) : (
this.props.instructions?.()
)}

{this.props.copyBtn && (
<div className="adyen-checkout__qr-loader__actions">
Expand Down
6 changes: 5 additions & 1 deletion packages/lib/src/components/internal/QRLoader/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { PaymentAmount } from '../../../types';
import Language from '../../../language/Language';
import { ActionHandledReturnObject } from '../../types';
import { h } from 'preact';

export interface QRLoaderProps {
delay?: number;
Expand All @@ -21,8 +22,11 @@ export interface QRLoaderProps {
classNameModifiers?: string[];
brandLogo?: string;
brandName?: string;
buttonLabel?: string;
introduction?: string;
instructions?: string;
redirectIntroduction?: string;
timeToPay?: string;
instructions?: string | (() => h.JSX.Element);
copyBtn?: boolean;
onActionHandled?: (rtnObj: ActionHandledReturnObject) => void;
}
Expand Down
10 changes: 8 additions & 2 deletions packages/lib/src/language/locales/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -301,5 +301,11 @@
"ancv.input.label": "تعريف ANCV الخاص بك",
"ancv.confirmPayment": "استخدم تطبيق ANCV الخاص بك لتأكيد الدفع.",
"ancv.form.instruction": "يعد تطبيق Cheque-Vacances ضروريًا للمصادقة على هذه المدفوعات.",
"ancv.beneficiaryId.invalid": "أدخل عنوان بريد إلكتروني صحيحًا أو معرف ANCV"
}
"ancv.beneficiaryId.invalid": "أدخل عنوان بريد إلكتروني صحيحًا أو معرف ANCV",
"payme.openPayMeApp": "أكمل الدفع في تطبيق PayMe من خلال الإذن بالدفع في التطبيق وانتظر التأكيد.",
"payme.redirectButtonLabel": "افتح تطبيق PayMe",
"payme.scanQrCode": "أكمل الدفع باستخدام رمز الاستجابة السريعة",
"payme.timeToPay": "رمز الاستجابة السريعة هذا صالح لـ %@",
"payme.instructions.steps": "افتح تطبيق PayMe. %@امسح رمز الاستجابة السريعة ضوئيًا للإذن بالدفع. %@أكمل عملية الدفع في التطبيق وانتظر التأكيد.",
"payme.instructions.footnote": "يرجى عدم إغلاق هذه الصفحة قبل إتمام الدفع"
}
10 changes: 8 additions & 2 deletions packages/lib/src/language/locales/cs-CZ.json
Original file line number Diff line number Diff line change
Expand Up @@ -297,5 +297,11 @@
"ancv.input.label": "Vaše identifikace ANCV",
"ancv.confirmPayment": "Pro potvrzení platby použijte aplikaci ANCV.",
"ancv.form.instruction": "K potvrzení této platby je nutná aplikace Cheque-Vacances.",
"ancv.beneficiaryId.invalid": "Zadejte platnou e-mailovou adresu nebo ID ANCV"
}
"ancv.beneficiaryId.invalid": "Zadejte platnou e-mailovou adresu nebo ID ANCV",
"payme.openPayMeApp": "Dokončete platbu autorizací v aplikaci PayMe a počkejte na potvrzení.",
"payme.redirectButtonLabel": "Otevřete aplikaci PayMe",
"payme.scanQrCode": "Dokončete platbu pomocí QR kódu",
"payme.timeToPay": "Tento QR kód je platný pro %@",
"payme.instructions.steps": "Otevřete aplikaci PayMe.%@Autorizujte platbu naskenováním QR kódu.%@Dokončete platbu v aplikaci a počkejte na potvrzení.",
"payme.instructions.footnote": "Nezavírejte prosím tuto stránku před dokončením platby."
}
10 changes: 8 additions & 2 deletions packages/lib/src/language/locales/da-DK.json
Original file line number Diff line number Diff line change
Expand Up @@ -298,5 +298,11 @@
"ancv.input.label": "Din ANCV-identifikation",
"ancv.confirmPayment": "Brug din ANCV-applikation til at bekræfte betalingen.",
"ancv.form.instruction": "Cheque-Vacances-applikationen er nødvendig for at validere denne betaling.",
"ancv.beneficiaryId.invalid": "Indtast en gyldig e-mailadresse eller ANCV-id"
}
"ancv.beneficiaryId.invalid": "Indtast en gyldig e-mailadresse eller ANCV-id",
"payme.openPayMeApp": "Gennemfør betalingen i PayMe-appen ved at godkende betalingen i appen og afvente bekræftelsen.",
"payme.redirectButtonLabel": "Åbn PayMe-appen",
"payme.scanQrCode": "Gennemfør din betaling med QR-kode",
"payme.timeToPay": "Denne QR-kode er gyldig i %@",
"payme.instructions.steps": "Åbn PayMe-appen.%@Scan QR-koden for at godkende betalingen.%@Gennemfør betalingen i appen, og afvent bekræftelse.",
"payme.instructions.footnote": "Luk ikke denne side, før betalingen er gennemført"
}
10 changes: 8 additions & 2 deletions packages/lib/src/language/locales/de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -297,5 +297,11 @@
"ancv.input.label": "Ihre ANCV-Identifikation",
"ancv.confirmPayment": "Bestätigen Sie die Zahlung mit Ihrem ANCV-Antrag.",
"ancv.form.instruction": "Zur Validierung dieser Zahlung ist der Antrag „Cheque-Vacances“ erforderlich.",
"ancv.beneficiaryId.invalid": "Geben Sie eine gültige E-Mail-Adresse oder ANCV-ID ein"
}
"ancv.beneficiaryId.invalid": "Geben Sie eine gültige E-Mail-Adresse oder ANCV-ID ein",
"payme.openPayMeApp": "Schließen Sie Ihre Zahlung in der PayMe-App ab, indem Sie die Zahlung in der App autorisieren und auf die Bestätigung warten.",
"payme.redirectButtonLabel": "Öffnen Sie die PayMe-App",
"payme.scanQrCode": "Schließen Sie Ihre Zahlung per QR-Code ab",
"payme.timeToPay": "Dieser QR-Code gilt für %@",
"payme.instructions.steps": "Öffnen Sie die PayMe-App.%@Scannen Sie den QR-Code, um die Zahlung zu autorisieren.%@Schließen Sie die Zahlung in der App ab und warten Sie auf eine Bestätigung.",
"payme.instructions.footnote": "Bitte schließen Sie diese Seite nicht, bevor die Zahlung abgeschlossen ist"
}
10 changes: 8 additions & 2 deletions packages/lib/src/language/locales/el-GR.json
Original file line number Diff line number Diff line change
Expand Up @@ -300,5 +300,11 @@
"ancv.input.label": "Η ταυτότητά σας ANCV",
"ancv.confirmPayment": "Χρησιμοποιήστε την εφαρμογή ANCV για επιβεβαίωση της πληρωμής.",
"ancv.form.instruction": "Η εφαρμογή Cheque-Vacances είναι απαραίτητη για επικύρωση της πληρωμής αυτής.",
"ancv.beneficiaryId.invalid": "Εισαγάγετε έγκυρη διεύθυνση email ή αναγνωριστικό ANCV"
}
"ancv.beneficiaryId.invalid": "Εισαγάγετε έγκυρη διεύθυνση email ή αναγνωριστικό ANCV",
"payme.openPayMeApp": "Ολοκληρώστε την πληρωμή σας στην εφαρμογή PayMe εξουσιοδοτώντας την πληρωμή στην εφαρμογή και περιμένετε την επιβεβαίωση.",
"payme.redirectButtonLabel": "Ανοίξτε την εφαρμογή PayMe",
"payme.scanQrCode": "Ολοκληρώστε την πληρωμή σας με κωδικό QR",
"payme.timeToPay": "Αυτός ο κωδικός QR ισχύει για %@",
"payme.instructions.steps": "Ανοίξτε την εφαρμογή PayMe.%@Σκανάρετε τον κωδικό QR για να εξουσιοδοτήσετε την πληρωμή.%@Ολοκληρώστε την πληρωμή στην εφαρμογή και περιμένετε την επιβεβαίωση.",
"payme.instructions.footnote": "Μην κλείσετε αυτήν τη σελίδα προτού ολοκληρωθεί η πληρωμή."
}
10 changes: 8 additions & 2 deletions packages/lib/src/language/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -302,5 +302,11 @@
"ancv.input.label": "Your ANCV identification",
"ancv.confirmPayment": "Use your ANCV application to confirm the payment.",
"ancv.form.instruction": "The Cheque-Vacances application is necessary to validate this payment.",
"ancv.beneficiaryId.invalid": "Enter a valid email address or ANCV ID"
}
"ancv.beneficiaryId.invalid": "Enter a valid email address or ANCV ID",
"payme.openPayMeApp": "Complete your payment in the PayMe app by authorizing the payment in the app and wait for the confirmation.",
"payme.redirectButtonLabel": "Open PayMe app",
"payme.scanQrCode": "Complete your payment by QR code",
"payme.timeToPay": "This QR code is valid for %@",
"payme.instructions.steps": "Open the PayMe app.%@Scan the QR code to authorize the payment.%@Complete the payment in the app and wait for confirmation.",
"payme.instructions.footnote": "Please do not close this page before the payment is completed"
}
10 changes: 8 additions & 2 deletions packages/lib/src/language/locales/es-ES.json
Original file line number Diff line number Diff line change
Expand Up @@ -292,5 +292,11 @@
"ancv.input.label": "Su identificación de la ANCV",
"ancv.confirmPayment": "Utilice su solicitud de la ANCV para confirmar el pago.",
"ancv.form.instruction": "La aplicación de Cheque-Vacances es necesaria para validar este pago.",
"ancv.beneficiaryId.invalid": "Introduzca una dirección de correo electrónico válida o un documento de identidad de la ANCV"
}
"ancv.beneficiaryId.invalid": "Introduzca una dirección de correo electrónico válida o un documento de identidad de la ANCV",
"payme.openPayMeApp": "Completa tu pago en la aplicación PayMe autorizando el pago en la aplicación y espera por la confirmación.",
"payme.redirectButtonLabel": "Abrir aplicación PayMe",
"payme.scanQrCode": "Completa tu pago con código QR",
"payme.timeToPay": "Este código QR es válido para %@",
"payme.instructions.steps": "Abre la aplicación PayMe.%@Escanea el código QR para autorizar el pago.%@Completa el pago en la aplicación y espera por la confirmación.",
"payme.instructions.footnote": "No cierres esta página antes de que se complete el pago"
}
10 changes: 8 additions & 2 deletions packages/lib/src/language/locales/fi-FI.json
Original file line number Diff line number Diff line change
Expand Up @@ -297,5 +297,11 @@
"ancv.input.label": "ANCV-tunnuksesi",
"ancv.confirmPayment": "Vahvista maksusi ANCV-sovelluksella.",
"ancv.form.instruction": "Tämän maksun vahvistaminen edellyttää Cheque-Vacances -sovelluksen.",
"ancv.beneficiaryId.invalid": "Anna kelvollinen sähköpostiosoite tai ANCV-tunnus"
}
"ancv.beneficiaryId.invalid": "Anna kelvollinen sähköpostiosoite tai ANCV-tunnus",
"payme.openPayMeApp": "Viimeistele maksu PayMe-sovelluksessa hyväksymällä maksu sovelluksessa, ja odota vahvistusta.",
"payme.redirectButtonLabel": "Avaa PayMe-sovellus",
"payme.scanQrCode": "Viimeistele maksusi QR-koodilla",
"payme.timeToPay": "Tämä QR-koodi on voimassa %@",
"payme.instructions.steps": "Avaa PayMe-sovellus.%@Hyväksy maksu skannaamalla QR-koodi.%@Viimeistele maksu sovelluksessa, ja odota vahvistusta.",
"payme.instructions.footnote": "Älä sulje tätä sivua ennen kuin maksu on suoritettu"
}
10 changes: 8 additions & 2 deletions packages/lib/src/language/locales/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -300,5 +300,11 @@
"ancv.input.label": "Votre identification ANCV",
"ancv.confirmPayment": "Utilisez votre application ANCV pour confirmer le paiement.",
"ancv.form.instruction": "L'application Chèque-Vacances est nécessaire pour valider ce paiement.",
"ancv.beneficiaryId.invalid": "Saisissez une adresse e-mail ou un identifiant ANCV valide"
}
"ancv.beneficiaryId.invalid": "Saisissez une adresse e-mail ou un identifiant ANCV valide",
"payme.openPayMeApp": "Finalisez votre paiement dans l'application PayMe en autorisant le paiement dans l'application, puis attendez la confirmation.",
"payme.redirectButtonLabel": "Ouvrir l'application PayMe",
"payme.scanQrCode": "Effectuez votre paiement avec un code QR",
"payme.timeToPay": "Ce code QR est valide pendant %@",
"payme.instructions.steps": "Ouvrez l'application PayMe.%@Scannez le code QR pour autoriser le paiement.%@Effectuez le paiement dans l'application et attendez la confirmation.",
"payme.instructions.footnote": "Veuillez ne pas fermer cette page avant que le paiement ne soit terminé."
}
10 changes: 8 additions & 2 deletions packages/lib/src/language/locales/hr-HR.json
Original file line number Diff line number Diff line change
Expand Up @@ -300,5 +300,11 @@
"ancv.input.label": "Vaša ANCV identifikacija",
"ancv.confirmPayment": "Koristite svoju ANCV aplikaciju za potvrdu plaćanja.",
"ancv.form.instruction": "Za potvrdu ove uplate neophodna je aplikacija Cheque-Vacances.",
"ancv.beneficiaryId.invalid": "Unesite valjanu adresu e-pošte ili ANCV ID"
}
"ancv.beneficiaryId.invalid": "Unesite valjanu adresu e-pošte ili ANCV ID",
"payme.openPayMeApp": "Dovršite plaćanje u aplikaciji PayMe: autorizirajte plaćanje u aplikaciji i pričekajte potvrdu.",
"payme.redirectButtonLabel": "Otvaranje aplikacije PayMe",
"payme.scanQrCode": "Dovršite svoje plaćanja QR kodom",
"payme.timeToPay": "Ovaj QR kôd vrijedi za %@",
"payme.instructions.steps": "Otvorite aplikaciju PayMe.%@Skenirajte QR kod za autorizaciju plaćanja.%@Dovršite plaćanje u aplikaciji i pričekajte potvrdu.",
"payme.instructions.footnote": "Ne zatvarajte ovu stranicu prije nego što se plaćanje završi"
}
10 changes: 8 additions & 2 deletions packages/lib/src/language/locales/hu-HU.json
Original file line number Diff line number Diff line change
Expand Up @@ -300,5 +300,11 @@
"ancv.input.label": "Az Ön ANCV-azonosítója",
"ancv.confirmPayment": "A fizetés megerősítéséhez használja az ANCV alkalmazást.",
"ancv.form.instruction": "A fizetés érvényesítéséhez a Cheque-Vacances alkalmazás szükséges.",
"ancv.beneficiaryId.invalid": "Adjon meg egy érvényes e-mail-címet vagy ANCV-azonosítót"
}
"ancv.beneficiaryId.invalid": "Adjon meg egy érvényes e-mail-címet vagy ANCV-azonosítót",
"payme.openPayMeApp": "A fizetésnek a PayMe alkalmazásban való engedélyezésével hajtsa végre a fizetést, és várja meg a visszaigazolást.",
"payme.redirectButtonLabel": "PayMe alkalmazás megnyitása",
"payme.scanQrCode": "Fizetés végrehajtása QR-kóddal",
"payme.timeToPay": "A QR-kód ennyi ideig érvényes: %@",
"payme.instructions.steps": "Nyissa meg a PayMe alkalmazást.%@A fizetés engedélyezéséhez olvassa be a QR-kódot.%@Hajtsa végre a fizetést az alkalmazásban, és várja meg a visszaigazolást.",
"payme.instructions.footnote": "A fizetés befejezése előtt ne zárja be ezt az oldalt"
}
Loading
Loading