BuzzPay.tsx raw

   1  import { AlertTriangleIcon, CopyIcon, ExternalLinkIcon } from "lucide-react";
   2  import React from "react";
   3  import { toast } from "sonner";
   4  import { AppDetailConnectedApps } from "src/components/connections/AppDetailConnectedApps";
   5  import { AppStoreDetailHeader } from "src/components/connections/AppStoreDetailHeader";
   6  import { appStoreApps } from "src/components/connections/SuggestedAppData";
   7  import Loading from "src/components/Loading";
   8  import QRCode from "src/components/QRCode";
   9  import { Alert, AlertDescription, AlertTitle } from "src/components/ui/alert";
  10  import { Button } from "src/components/ui/button";
  11  import { LoadingButton } from "src/components/ui/custom/loading-button";
  12  import { Input } from "src/components/ui/input";
  13  import { Label } from "src/components/ui/label";
  14  import { useApps } from "src/hooks/useApps";
  15  import { copyToClipboard } from "src/lib/clipboard";
  16  import { createApp } from "src/requests/createApp";
  17  import { handleRequestError } from "src/utils/handleRequestError";
  18  import { openLink } from "src/utils/openLink";
  19  
  20  export function BuzzPay() {
  21    const [name, setName] = React.useState("");
  22    const [isLoading, setLoading] = React.useState(false);
  23    const { data: appsData, mutate: reloadApps } = useApps(undefined, undefined, {
  24      appStoreAppId: "buzzpay",
  25    });
  26    const [posUrl, setPosUrl] = React.useState("");
  27  
  28    const appStoreApp = appStoreApps.find((app) => app.id === "buzzpay");
  29    if (!appStoreApp) {
  30      return null;
  31    }
  32    if (!appsData) {
  33      return <Loading />;
  34    }
  35  
  36    const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
  37      event.preventDefault();
  38      setLoading(true);
  39      (async () => {
  40        try {
  41          const createAppResponse = await createApp({
  42            name,
  43            scopes: ["get_info", "lookup_invoice", "make_invoice"],
  44            isolated: true,
  45            metadata: {
  46              app_store_app_id: "buzzpay",
  47            },
  48          });
  49  
  50          setPosUrl(
  51            `https://pos.albylabs.com/#/?nwc=${btoa(createAppResponse.pairingUri)}&label=${encodeURIComponent(name)}`
  52          );
  53  
  54          await reloadApps();
  55  
  56          toast("BuzzPay PoS connection created");
  57        } catch (error) {
  58          handleRequestError("Failed to create PoS connection", error);
  59        }
  60        setLoading(false);
  61      })();
  62    };
  63  
  64    return (
  65      <div className="grid gap-5">
  66        <AppStoreDetailHeader appStoreApp={appStoreApp} contentRight={null} />
  67        {posUrl && (
  68          <div className="max-w-lg flex flex-col gap-5">
  69            <p>
  70              Open the PoS link below and share it with your employees and devices
  71              you want to use the PoS with.
  72            </p>
  73            <Alert>
  74              <AlertTriangleIcon />
  75              <AlertTitle>
  76                Save this link and add it to your home screen
  77              </AlertTitle>
  78              <AlertDescription>
  79                This link will only be shown once and can't be retrieved
  80                afterwards. Please make sure to keep it somewhere safe.
  81              </AlertDescription>
  82            </Alert>
  83  
  84            <div className="flex flex-col items-center">
  85              <QRCode value={posUrl} />
  86            </div>
  87            <div className="flex flex-col gap-3">
  88              <Input disabled readOnly type="text" value={posUrl} />
  89              <Button
  90                className="w-full"
  91                onClick={() => copyToClipboard(posUrl)}
  92                variant="outline"
  93              >
  94                <CopyIcon />
  95                Copy
  96              </Button>
  97              <Button
  98                className="w-full"
  99                onClick={() => openLink(posUrl)}
 100                variant="outline"
 101              >
 102                <ExternalLinkIcon />
 103                Open
 104              </Button>
 105            </div>
 106          </div>
 107        )}
 108        {!posUrl && (
 109          <>
 110            <div className="max-w-lg flex flex-col gap-5">
 111              <p className="text-muted-foreground">
 112                BuzzPay works by creating read-only connections to your Alby Hub.
 113              </p>
 114              <ul className="text-muted-foreground">
 115                <li>🔒 Allow employees to collect but never spend your funds</li>
 116                <li>🔗 Sharable link that can be used on any device</li>
 117                <li>âš¡ Lightning fast transactions directly to your Alby Hub</li>
 118              </ul>
 119              <form
 120                onSubmit={handleSubmit}
 121                className="flex flex-col items-start gap-5 max-w-lg"
 122              >
 123                <div className="w-full grid gap-1.5">
 124                  <Label htmlFor="name">PoS Name</Label>
 125                  <Input
 126                    autoFocus
 127                    type="text"
 128                    name="name"
 129                    value={name}
 130                    id="name"
 131                    onChange={(e) => setName(e.target.value)}
 132                    required
 133                    autoComplete="off"
 134                  />
 135                </div>
 136                <LoadingButton loading={isLoading} type="submit">
 137                  Next
 138                </LoadingButton>
 139              </form>
 140            </div>
 141            <AppDetailConnectedApps appStoreApp={appStoreApp} showTitle />
 142          </>
 143        )}
 144      </div>
 145    );
 146  }
 147