/ packages / frontend / src / components / RelayClientTestPage.tsx
RelayClientTestPage.tsx
  1  import React, { useEffect, useState } from "react";
  2  import { IRelayEndpoint, RelayClient } from "@massmarket/client";
  3  import type { WalletClient } from "viem";
  4  import type { Account } from "viem/accounts";
  5  
  6  interface RelayClientTestPageProps {
  7    relayEndpoint: IRelayEndpoint;
  8    walletClient: WalletClient;
  9    keycard: Account;
 10    shopId: bigint;
 11  }
 12  
 13  function relativeTime(diff: number) {
 14    // Convert milliseconds to seconds
 15    const seconds = Math.floor(diff / 1000);
 16  
 17    if (seconds < 60) {
 18      return `${seconds} second${seconds !== 1 ? "s" : ""} ago`;
 19    }
 20  
 21    const minutes = Math.floor(seconds / 60);
 22    if (minutes < 60) {
 23      return `${minutes} minute${minutes !== 1 ? "s" : ""} ago`;
 24    }
 25  
 26    const hours = Math.floor(minutes / 60);
 27    if (hours < 24) {
 28      return `${hours} hour${hours !== 1 ? "s" : ""} ago`;
 29    }
 30  
 31    const days = Math.floor(hours / 24);
 32    return `${days} day${days !== 1 ? "s" : ""} ago`;
 33  }
 34  
 35  const RelayClientTestPage: React.FC<RelayClientTestPageProps> = ({
 36    relayEndpoint,
 37    walletClient,
 38    keycard,
 39    shopId,
 40  }) => {
 41    const [connectionStatus, setConnectionStatus] = useState<
 42      "idle" | "connecting" | "connected" | "failed" | "disconnected"
 43    >("idle");
 44    const [lastPingReceived, setLastPingReceived] = useState<string>("Never");
 45    const [error, setError] = useState<string | null>(null);
 46    const [client, setClient] = useState<RelayClient | null>(null);
 47  
 48    useEffect(() => {
 49      const newClient = new RelayClient({
 50        relayEndpoint,
 51        walletClient,
 52        keycard,
 53        shopId,
 54      });
 55  
 56      setClient(newClient);
 57      setConnectionStatus("connecting");
 58  
 59      // Connect to relay
 60      newClient.connect((error: Event) => {
 61        setError((error as ErrorEvent).message);
 62        setConnectionStatus("failed");
 63      }).then(() => {
 64        setConnectionStatus("connected");
 65      });
 66  
 67      // Cleanup function to disconnect when component unmounts
 68      return () => {
 69        if (client) {
 70          client.disconnect().catch((err) => {
 71            console.error("Error disconnecting:", err);
 72          });
 73        }
 74      };
 75    }, [relayEndpoint, walletClient, keycard, shopId]);
 76  
 77    const handleDisconnect = async () => {
 78      if (client) {
 79        try {
 80          await client.disconnect();
 81          setConnectionStatus("disconnected");
 82        } catch (err: unknown) {
 83          setError(err instanceof Error ? err.message : String(err));
 84          setConnectionStatus("failed");
 85          setLastPingReceived("Never");
 86        }
 87      }
 88    };
 89  
 90    useEffect(() => {
 91      const timer = setInterval(() => {
 92        if (client && client.stats.pingsReceived > 0) {
 93          console.log({ stats: client.stats });
 94          const now = new Date();
 95          const diff = now.getTime() - client?.stats.lastPingReceived.getTime();
 96          setLastPingReceived(relativeTime(diff));
 97        }
 98      }, 1000);
 99  
100      return () => {
101        clearInterval(timer);
102      };
103    }, [client]);
104  
105    return (
106      <div data-testid="relay-client-tester">
107        <div data-testid="connection-status">Status: {connectionStatus}</div>
108        {error && <div data-testid="connection-error">Error: {error}</div>}
109        {connectionStatus === "connected" && (
110          <button
111            type="button"
112            data-testid="disconnect-button"
113            onClick={handleDisconnect}
114          >
115            Disconnect
116          </button>
117        )}
118        <div data-testid="stats-last-ping-received">
119          Last ping received: {lastPingReceived}
120        </div>
121      </div>
122    );
123  };
124  
125  export default RelayClientTestPage;