frames-react icon indicating copy to clipboard operation
frames-react copied to clipboard

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

Open yaman3bd opened this issue 1 year ago • 1 comments

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

yaman3bd avatar Aug 03 '23 17:08 yaman3bd

I tried several ways to add the script but each time I run into unexpected error: used nextjs/head to add the script:

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

but if I leave the page and visit it again I get:

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

I even tried to use a custom solution to load the script manually on page mount and wait for it to load:

import { useEffect } from "react";

const useExternalScripts = (
  src: string,
  attributes: Record<string, string> = {},
  onload: (() => void) | null = null,
  appendToHead: boolean = false
) => {
  useEffect(() => {
    const tempScript = document.createElement("script");

    tempScript.setAttribute("src", src);
    Object.keys(attributes).forEach((att) => {
      tempScript.setAttribute(att, attributes[att]);
    });
    tempScript.onload = () => {
      if (onload) {
        onload();
      }
    };
    if (appendToHead) {
      document.head.appendChild(tempScript);
    } else {
      document.body.appendChild(tempScript);
    }

    // Clean up the script when the component unmounts
    return () => {
      if (tempScript) {
        tempScript.remove();
      }
    };
  }, [src, attributes, onload, appendToHead]);
};

export default useExternalScripts;

usage:

import { useState } from "react";

import { CardFrame } from "frames-react";

import useExternalScripts from "@/hooks/useExternalScripts";

const CardCheckout = () => {
  const [loaded, setLoaded] = useState<boolean>(false);

  useExternalScripts(
    "https://cdn.checkout.com/js/framesv2.min.js",
    {},
    () => {
      setLoaded(true);
    },
    true
  );

  if (!loaded) {
    return <div>Loading...</div>;
  }

  return (
    <div className="overflow-hidden">
      <CardFrame />
    </div>
  );
};

export default CardCheckout;

but in the custom solution when I submit the form I get

Uncaught (in promise) Card form invalid

I even logged the event I get from events and the form is valid: cardValidationChanged:

{
  isValid: true,
  isElementValid: {
    cardNumber: true,
    expiryDate: true,
    cvv: true,
    schemeChoice: true
  }
};

frameValidationChanged:

{
  element: "cvv",
  isValid: true,
  isEmpty: false,
  isFormValid: true,
  isFormEmpty: false
};

so the best thing to resolve all these issues is to auto-load the script

yaman3bd avatar Aug 03 '23 17:08 yaman3bd