ConnectAppCard.tsx raw

   1  import { CheckIcon, CopyIcon, EyeIcon } from "lucide-react";
   2  import { useEffect, useState } from "react";
   3  import { AppStoreApp } from "src/components/connections/SuggestedAppData";
   4  import Loading from "src/components/Loading";
   5  import QRCode from "src/components/QRCode";
   6  import { Badge } from "src/components/ui/badge";
   7  import { Button } from "src/components/ui/button";
   8  import {
   9    Card,
  10    CardContent,
  11    CardHeader,
  12    CardTitle,
  13  } from "src/components/ui/card";
  14  import { LinkButton } from "src/components/ui/custom/link-button";
  15  import { copyToClipboard } from "src/lib/clipboard";
  16  import { cn } from "src/lib/utils";
  17  import { App } from "src/types";
  18  
  19  export function ConnectAppCard({
  20    app,
  21    pairingUri,
  22    appStoreApp,
  23  }: {
  24    app: App;
  25    pairingUri: string;
  26    appStoreApp?: AppStoreApp;
  27  }) {
  28    const [timeout, setTimeout] = useState(false);
  29    const [isQRCodeVisible, setIsQRCodeVisible] = useState(false);
  30    const copy = () => {
  31      copyToClipboard(pairingUri);
  32    };
  33  
  34    useEffect(() => {
  35      const timeoutId = window.setTimeout(() => {
  36        setTimeout(true);
  37      }, 30000);
  38  
  39      return () => window.clearTimeout(timeoutId);
  40    }, []);
  41  
  42    return (
  43      <Card className="w-full">
  44        <CardHeader>
  45          <CardTitle className="text-center">Connection Secret</CardTitle>
  46        </CardHeader>
  47        <CardContent className="flex flex-col items-center gap-5">
  48          {!app.lastUsedAt ? (
  49            <>
  50              <div className="flex flex-row items-center gap-2 text-sm z-10">
  51                <Loading className="size-4" />
  52                <p>Waiting for app to connect</p>
  53              </div>
  54              {timeout && (
  55                <div className="text-sm flex flex-col gap-2 items-center text-center">
  56                  Connecting is taking longer than usual.
  57                  <LinkButton to={`/apps/${app?.id}`} variant="secondary">
  58                    Continue anyway
  59                  </LinkButton>
  60                </div>
  61              )}
  62            </>
  63          ) : (
  64            <Badge variant="positive">
  65              <CheckIcon />
  66              App connected
  67            </Badge>
  68          )}
  69          {!appStoreApp?.hideConnectionQr && (
  70            <div className="relative">
  71              <div
  72                className={cn(!isQRCodeVisible && "blur-md cursor-pointer")}
  73                onClick={() => setIsQRCodeVisible(true)}
  74              >
  75                <QRCode value={pairingUri} />
  76                {appStoreApp && (
  77                  <img
  78                    src={appStoreApp.logo}
  79                    className="absolute w-12 h-12 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-muted p-1 rounded-xl"
  80                  />
  81                )}
  82              </div>
  83              {!isQRCodeVisible && (
  84                <Button
  85                  onClick={() => {
  86                    setIsQRCodeVisible(true);
  87                  }}
  88                  className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2"
  89                >
  90                  <EyeIcon />
  91                  Reveal QR
  92                </Button>
  93              )}
  94            </div>
  95          )}
  96          <div className="flex gap-2">
  97            <Button onClick={copy} variant="outline">
  98              <CopyIcon />
  99              Copy Connection Secret
 100            </Button>
 101            {/* For now not showing open in-app, only works well on Android, not on Desktop or iOS */}
 102            {/* <ExternalLinkButton to={pairingUri} variant="outline">
 103              <ExternalLinkIcon />
 104              Open In App
 105            </ExternalLinkButton> */}
 106          </div>
 107        </CardContent>
 108      </Card>
 109    );
 110  }
 111