GithubHelp home page GithubHelp logo

checkout / frames-react Goto Github PK

View Code? Open in Web Editor NEW
29.0 5.0 13.0 3.28 MB

React wrapper of Checkout.com Frames.

Home Page: https://docs.checkout.com/integrate/frames

License: MIT License

HTML 2.28% CSS 11.94% TypeScript 70.65% JavaScript 15.13%
payments react secure-payments credit-card

frames-react's Introduction

This project is a minimalistic React wrapper of Checkout.com Frames.

🚀 Install

npm install frames-react

🌐 Load the CDN

Make sure that you load the CDN before you mount the Frames components. You can add it for example in your index.html file.

<script src="https://cdn.checkout.com/js/framesv2.min.js"></script>

If you use server side rendering like Next you can add it in the Head:

<Head>
    <script src="https://cdn.checkout.com/js/framesv2.min.js"></script>
</Head>

✨ Import the components

import { Frames, CardNumber, ExpiryDate, Cvv } from 'frames-react';

💪 Example Usage

Make sure you wrap the card input components inside Frames wrapper component.

<Frames
    config={{
        debug: true,
        publicKey: 'pk_test_6e40a700-d563-43cd-89d0-f9bb17d35e73',
        localization: {
            cardNumberPlaceholder: 'Card number',
            expiryMonthPlaceholder: 'MM',
            expiryYearPlaceholder: 'YY',
            cvvPlaceholder: 'CVV',
        },
        style: {
            base: {
                fontSize: '17px',
            },
        },
    }}
    ready={() => {}}
    frameActivated={(e) => {}}
    frameFocus={(e) => {}}
    frameBlur={(e) => {}}
    frameValidationChanged={(e) => {}}
    paymentMethodChanged={(e) => {}}
    cardValidationChanged={(e) => {}}
    cardSubmitted={() => {}}
    cardTokenized={(e) => {}}
    cardTokenizationFailed={(e) => {}}
    cardBinChanged={(e) => {}}
>
    <CardNumber />
    <ExpiryDate />
    <Cvv />
</Frames>

Trigger tokenisation

To trigger the tokenisation, this wrapper has a static methods called submitCard() Here is a full example of the full flow:

<Frames
    config={{
        publicKey: 'pk_test_6e40a700-d563-43cd-89d0-f9bb17d35e73',
    }}
    cardTokenized={(e) => {
        alert(e.token);
    }}
>
    <CardNumber />
    <ExpiryDate />
    <Cvv />

    <button
        onClick={() => {
            Frames.submitCard();
        }}
    >
        PAY GBP 25.00
    </button>
</Frames>

Single Line component

If you want to use Frame in single frame mode you cna do it like this:

<Frames
    config={{
        publicKey: 'pk_test_6e40a700-d563-43cd-89d0-f9bb17d35e73',
    }}
    cardTokenized={(e) => {
        alert(e.token);
    }}
>
    <CardFrame />

    <button
        onClick={() => {
            Frames.submitCard();
        }}
    >
        PAY GBP 25.00
    </button>
</Frames>

For Carte Bancaire

If you want to accept Carte Bancaire you can pass the schemeChoice parameter in the config. This will render the scheme icon with a dropdown, and customers will be able to select their scheme. Make sure your CSS is not interfering with the display of the dropdown.

import React from 'react';
import { Frames, CardNumber, ExpiryDate, Cvv, CardFrame } from 'frames-react';

import './App.css';

function App() {
    return (
        <div className="App">
            <Frames
                config={{
                    publicKey: 'pk_sbox_ogynfaoply5o6ksuw3d3hcee3ez',
                    schemeChoice: true,
                }}
                cardTokenized={(e) => {
                    alert(e.token);
                }}
            >
                <CardNumber />
                <div className="date-and-code">
                    <ExpiryDate />
                    <Cvv />
                </div>

                {/* Or if you want to use single frames: */}
                {/* <CardFrame /> */}

                <button
                    id="pay-button"
                    onClick={() => {
                        Frames.submitCard();
                    }}
                >
                    PAY GBP 25.00
                </button>
            </Frames>
        </div>
    );
}

export default App;

💳 Cardholder

If you need to inject the cardholder name on go, for cases where you render the payment form at the same time as the input for the billing and cardholder name, you can simply update the props and Frames will reflect the latest changes

const [cardholder, setCardholder] = useState({
   name: '',
   phone: '',
   billingAddress: {
       addressLine1: '',
   },
});
...
<Frames
   config={{
       cardholder: {
           name: cardholder.name,
           phone: cardholder.phone,
           billingAddress: cardholder.billingAddress,
       }
   }}
   ...
/>
...
<ExampleInput
   onChange={(e) => {
       setCardholder({
           name: e.target.value,
           phone: '7123456789',
           billingAddress: {
               addressLine1: 'London Street',
           },
       });
   }}
/>

The props

prop description
config The config is an object following the reference of Checkout.com Frames.
ready Triggered when Frames is registered on the global namespace and safe to use.
frameActivated Triggered when the form is rendered.
frameFocus Triggered when an input field receives focus. Use it to check the validation status and apply the wanted UI changes.
frameBlur Triggered after an input field loses focus. Use it to check the validation status and apply the wanted UI changes.
frameValidationChanged Triggered when a field's validation status has changed. Use it to show error messages or update the UI.
paymentMethodChanged Triggered when a valid payment method is detected based on the card number being entered. Use this event to change the card icon.
cardValidationChanged Triggered when the state of the card validation changes.
cardSubmitted Triggered when the card form has been submitted.
cardTokenized Triggered after a card is tokenized.
cardBinChanged Triggered when the user inputs or changes the first 8 digits of a card.

Static functions

function description
init Initializes (or re-initializes) Frames.
isCardValid Returns the state of the card form validation.
submitCard Submits the card form if all form values are valid.
addEventHandler Adds a handler that is called when the specified event is triggered.
removeEventHandler Removes a previously added handler from an event by providing the event name and handler as arguments in the method.
removeAllEventHandlers Removes all handlers added to the event specified.
enableSubmitForm Retains the entered card details and allows you to resubmit the payment form.

frames-react's People

Contributors

ioan-ghisoi-cko avatar ioan-ghisoi avatar punit-shah-cko avatar nicolas-maalouf-cko avatar ryan-gregory-cko avatar tom-finlayson-cko avatar

Stargazers

 avatar Ömer Faruk Şahin avatar Daniil Pokrovsky avatar Vincent Lyons avatar Sami Diab avatar Joseph avatar Pooya Golchian avatar  avatar Rizwan Zaheer avatar  avatar Hatem Ismail avatar  avatar  avatar  avatar fenricage avatar  avatar  avatar Abhishek Sah avatar  avatar Jiyan Akgül avatar Mike avatar  avatar  avatar Christian Baldwin avatar  avatar Matt Delmarter avatar Giovanni Mogna avatar Suke Han avatar  avatar

Watchers

James Cloos avatar Guillaume Pousaz avatar Riaz Bordie avatar  avatar  avatar

frames-react's Issues

In wrapper Frames.submitCard() does not return a Promise like in the vanilla Checkout.com frames library

Hi Checkout,

while using react wrapper for the library I was not able to use return value of Frames.submitCard() so I could reuse card token string from the response, as documented in frames reference

Is there another way to do it with react wrapper or is it a bug?

I was looking at the code of Frames.tsx and on line 128 i guess the easiest fix would be to just

    static submitCard = () => {
        return window.Frames.submitCard();
    };

instead of not returning anything

Thank you,
Ivo

Manually disable the components

How do I manually disable the CardNumber, ExpiryDate & Cvv components? There's no prop defined in the documentation to do so.

Typescript

Is there any plans regarding adding typescript typedef in this repo ?

Arabic support for Frames

How can I add Arabic support for Frames?

I know that I can use placeholders for the field names:

localization: {
              cardNumberPlaceholder: 'Arabic string',
              expiryMonthPlaceholder: 'MM',
              expiryYearPlaceholder: 'YY',
              cvvPlaceholder: 'CVV'
            },

But I am not able to change the direction to RTL. Since inside the iFrame the lang is still set to EN-GB (default locale) even though I use Arabic placeholders. So my input fields and their placeholders are not positioned correctly

<html lang="EN-GB">

Screen Shot 2021-05-05 at 4 33 55 AM

Is there a way to change the error message? (Card form invalid)

I would like to change the "Card form invalid" error to an especific error when the card number/cvc/expiry is invalid.
Is there a way of doing that, or should I manually add a state and use "frameValidationChanged", for example?

Thank you in advance.

Error As(framesv2) The card frame does not exist in the DOM.

hey.

we're facing such an issue in our system with Frames implemented:

<Frames
        config={createCheckoutComFrameConfig({
          publicKey,
          localization: {
            cardNumberPlaceholder: 'E.g. 1234 5678 9123 4567',
            expiryMonthPlaceholder: `${translate('month')} (MM)`,
            expiryYearPlaceholder: `${translate('year')} (YY)`,
            cvvPlaceholder: 'E.g. 123',
          },
        })}
        cardTokenized={onCardTokenizedHandler}
        frameValidationChanged={onFrameValidationChangedHandler}
        ready={onReadyHandler}
        cardSubmitted={onCardSubmittedHandler}
      >

it only happens on mobile devices, it might happen quite randomly and not often.

did somebody face the same issue?

Autofill CSS passed is not getting applied

Hi,

I'm passing the autofill styles to the style object like this -

        <Frames
                config={
                  {
                    publicKey: checkoutPublicKey,
                    localization: {
                      cardNumberPlaceholder: 'Enter card number',
                      expiryMonthPlaceholder: 'MM ',
                      expiryYearPlaceholder: ' YY',
                      cvvPlaceholder: 'CVV',
                    },
                    style: {
                      base: {
                        // some styles
                      },
                      autofill: {
                        backgroundColor: 'rgba(255,255,255,0.1) !important',
                      },
                      }
                      }}

Still when the credit card information is auto filled in chrome, a white mask is getting applied over the card field.

Lazy load of cdn

I could not find a way to lazy load the checkout library, did I miss something or it's not supported yet ? Alternatively could we have a way to listen for a onScriptReady callback ? This way we could at least put the script load in the body rather than the head

Enhancement: Improve 'frames-react' to Handle Script Loading from CDN Automatically

I am having issues when I want to use the frames I always get this error:

Frames was used before the script (from the CDN) was loaded completely 

so it would be better if frames-react also handles loading the script from the CDN and then initialize the frames instead of me having to wait for it to load, and running into unexpected issues

How can i get CVV in frames react. It is not allowing me to access.

   I applied the onchange, useRef but didn't find any solution to access the CVV is there any method. I have to send the CVV in 
   payload to backend.I'm getting few details from cardTokenized but can't access the CVV
   
   
   <Frames
          config={{
            debug: true,
            publicKey: "",
            localization: {
              cardNumberPlaceholder: "",
              expiryMonthPlaceholder: "",
              expiryYearPlaceholder: "",
              cvvPlaceholder: "CVV",
            },
            style: {
              base: {
                fontSize: "14px",
                background: "#e5eff2",
                color: "#101e8e",
                opacity: "1",
                padding: "18px 18px 18px 47px",
                margin: "0",
                outline: "none",
                border: "1px solid #b6bfdc",
                width: "100%",
                height: "35px",
              },
            },
          }}
          cardTokenized={(e) => {
            paymentsubmit(e);
          }}
        >
          <div style={{ background: "white" }}>
            <div
              style={{
                display: "flex",
                flexDirection: "column",
                height: "400px",
              }}
            >
              <div
                style={{
                  display: "flex",
                  flexDirection: "column",
                  padding: "20px",
                }}
              >
                <div className="quick-pay-amount-to-pay-screen1">
                  <p>Amount </p>
                  <p>AED {totalAmountToPay.toFixed(2)} </p>
                </div>
                <hr className="hr-add-card" />

                <div className="quick-pay-card-number-field1">
                  <p
                    style={{
                      fontSize: `${0.875}rem`,
                      fontFamily: "Segoe UI",
                      color: "#101E8E",
                      fontWeight: "700",
                      marginBottom: "2px",
                    }}
                  >
                    Credit / Debit Card Number
                  </p>
                  <div className="quick-pay-card-number-field1-icon">
                    <img src={ccIcon} />
                  </div>
                  <CardNumber style={{ height: "40px" }} />
                </div>
                <div
                  style={{
                    display: "flex",
                    width: "100%",
                    marginTop: "30px",
                  }}
                >
                  <div style={{ display: "flex", flexDirection: "column" }}>
                    <p
                      style={{
                        fontSize: `${0.875}rem`,
                        fontFamily: "Segoe UI",
                        color: "#101E8E",
                        fontWeight: "700",
                      }}
                    >
                      Expiry Date
                    </p>
                    <ExpiryDate
                      style={{ width: "90%" }}
                      className="ExpiryDate-field"
                    />
                  </div>
                  <div style={{ position: "relative" }}>
                    <p
                      style={{
                        fontSize: `${0.875}rem`,
                        fontFamily: "Segoe UI",
                        color: "#101E8E",
                        fontWeight: "700",
                      }}
                    >
                      CVV Number
                    </p>
                    <div className="cvc-image-background-color">
                      <img src={cvv} />
                    </div>

                    <Cvv
              
                      type="text"
                      className="ExpiryDate-field"
                    />
                  </div>
                </div>
                <div className="quick-pay-card-number-field2">
                  <p
                    style={{
                      fontSize: `${0.875}rem`,
                      fontFamily: "Segoe UI",
                      color: "#101E8E",
                      fontWeight: "700",
                      marginBottom: "2px",
                    }}
                  >
                    Email Address
                  </p>
                  <input
                    onChange={(e) => handleEmailChange(e)}
                    type="email"
                    className=""
                    value={mail}
                  />
                </div>
                <Button
                  className="pay-now"
                  onClick={() => {
                    Frames.submitCard();
                  }}
                  style={{ padding: "20px", boxShadow: "none" }}
                >
                  PAY NOW
                </Button>
              </div>
            </div>
          </div>
        </Frames>

401 Response When attempting to tokenize card

I am getting the following response in the console when attempting to tokenize the card

my implementation:
HTML
`

<script src="https://cdn.checkout.com/js/framesv2.min.js"></script> `

React
<Frames config={{ debug: true, publicKey: 'xxxxx=', }} cardTokenized={(e) => { console.log(e.token); this.paymentRequest(e.token); }} cardSubmitted={() => { this.setState({ isLoading: true }) }} > <div style={{ display: "flex", flexDirection: "column" }}> <CardFrame /> <Button variant='contained' onClick={() => { Frames.submitCard(); }}> Pay ${(this.state.cartItems.reduce((a, v) => a = a + v.price, 0))} </Button> </div> </Frames>

Error Response in console
POST https://api.sandbox.checkout.com/tokens 401
D @ shared.js:256
(anonymous) @ Form.js:589
(anonymous) @ Form.js:257
VM8:1 Uncaught SyntaxError: Unexpected end of JSON input
at JSON.parse ()
at D.g.onreadystatechange (shared.js:235:29)

Any idea what might be causing this?

I checked the public key 3 times, still go this issue.

FramesLanguages type does not list all supported languages

In types : checkout/frames-react/src/frames/types/types.tsx the FramesLanguages type states the languages are

export type FramesLanguages = 'EN-GB' | 'ES-ES' | 'FR-FR' | 'DE-DE' | 'KR-KR' | 'IT-IT' | 'NL-NL';

but according to the Get started with Frames

the available languages that one can use are

Arabic = AR
Chinese Simplified = ZH-CH
Chinese Traditional (Hong Kong) = ZH-HK
Chinese Traditional (Taiwan) = ZH-TW
Danish = DA-DK
Dutch = NL-NL
English = EN-GB
Filipino = FIL-PH
Finnish - FI-FI
French = FR-FR
German = DE-DE
Hindi = HI-IN
Indonesian = ID-ID
Italian = IT-IT
Japanese = JA-JP
Korean = KO-KR
Malay = MS-MY
Norwegian Bokmål = NB-NO
Spanish = ES-ES
Swedish = SV-SE
Thai = TH-TH
Vietnamese = VI-VN

I've tried passing in the SV-SE for example and got the correct localization in the frames fields, so I think only change needed is to extend the type.

Invalid type for FrameCardTokenizedEvent.name

types/types.d.ts
export interface FrameCardTokenizedEvent { type: string; token: string; expires_on: string; expiry_month: string; expiry_year: string; scheme?: Scheme; scheme_local: string; last4: string; preferred_scheme?: PreferredScheme; bin: string; card_type?: CardType; card_category?: CardCategory; issuer?: string; issuer_country?: string; product_id?: string; product_type?: string; billing_address?: GatewayBillingAddress; phone?: GatewayPhone; name?: GatewayBillingAddress; }
type for name is incorrect, unable to get card holder name

Cross error blocks frames origin

when typing card name and other information we got this error in console but the process of payment done successfully could we fix this error ?
checkout

Doc dead links

Hi,

There are several dead links to the documentation in the project.
I modified the Readme and did a PR, but I think there are more to replace.

FramesInitProps.schemeChoice does not allow boolean

Hello,

On the documentation, schemeChoice can be enabled on Frames with a boolean like this :

Frames.init({
   schemeChoice: true,
   // rest of the configuration...
});

But the current version of the lib declares FramesInitProps.schemeChoice like as a SelectorChoiceType which does not allow simple boolean.

Change font of inputs

Could you add possibility to change inputs' font ? This doesn't seem to work for now:

CleanShot 2023-06-07 at 15 45 31
CleanShot 2023-06-07 at 15 45 35

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.