Skip to content

Instantly share code, notes, and snippets.

@jmont96
Created September 12, 2025 18:53
Show Gist options
  • Select an option

  • Save jmont96/18238b257e15a7fa93ccc45b3885873e to your computer and use it in GitHub Desktop.

Select an option

Save jmont96/18238b257e15a7fa93ccc45b3885873e to your computer and use it in GitHub Desktop.
"use client";
import axios from "axios";
import { useCallback, useEffect, useRef, useState } from "react";
export default function CheckoutLinkPlaceholderDemoPage() {
const [sessionKey, setSessionKey] = useState<string | null>(null);
const [link, setLink] = useState<string | null>(null);
const [iframeLoaded, setIframeLoaded] = useState(false);
const initiateCheckout = useCallback(async () => {
// Get Session Key
const session = await axios.get("/api/session-key");
setSessionKey(session.data);
// Get Checkout Link for iFrame
const checkoutLink = await axios.get("/api/link");
setLink(checkoutLink.data.link);
}, []);
useEffect(() => {
initiateCheckout();
}, [initiateCheckout]);
const handleMessage = useCallback((event: MessageEvent) => {
// Try to parse if it's a string
let parsedData = event.data;
if (typeof event.data === "string") {
try {
parsedData = JSON.parse(event.data);
} catch (e) {
console.log("Failed to parse as JSON:", e);
}
}
const { method } = parsedData || {};
switch (method) {
case "loaded":
setTimeout(() => {
setIframeLoaded(true);
}, 1000);
break;
}
}, []);
useEffect(() => {
window.addEventListener("message", handleMessage);
return () => {
window.removeEventListener("message", handleMessage);
};
}, [handleMessage]);
const IFrameRef = useRef<HTMLIFrameElement | null>(null);
const handleIframeLoad = () => {
if (IFrameRef.current) IFrameRef.current.style.opacity = "1";
};
if (!sessionKey || !link) {
return <div>Loading...</div>;
}
return (
<div className="relative w-full h-screen bg-white flex">
<div className="h-180 w-100 m-auto relative">
<iframe
allow={"payment;camera;clipboard-write"}
src={link}
onLoad={handleIframeLoad}
ref={IFrameRef}
className="w-full h-full border-none"
style={{
width: "100%",
height: "100%",
opacity: 0,
transition: "opacity 300ms linear",
}}
/>
{!iframeLoaded && (
<div
className={`
absolute top-0 left-0 w-full h-full bg-zinc-100
flex flex-col items-center justify-center z-10
transition-opacity duration-500 ease-out border border-zinc-200
${iframeLoaded ? "opacity-0" : "opacity-100"}
`}
>
{/* Skeleton Header */}
<div className="w-3/5 h-10 bg-zinc-300 rounded-lg mb-5 animate-pulse" />
{/* Skeleton Content Blocks */}
<div className="w-4/5 flex flex-col gap-4">
<div className="w-full h-16 bg-zinc-300 rounded-lg animate-pulse" />
<div className="w-3/4 h-10 bg-zinc-300 rounded-lg animate-pulse" />
<div className="w-11/12 h-20 bg-zinc-300 rounded-lg animate-pulse" />
<div className="w-1/2 h-8 bg-zinc-300 rounded-lg animate-pulse" />
</div>
</div>
)}
</div>
</div>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment