About.tsx raw

   1  import { ExternalLinkIcon } from "lucide-react";
   2  import ExternalLink from "src/components/ExternalLink";
   3  import Loading from "src/components/Loading";
   4  import SettingsHeader from "src/components/SettingsHeader";
   5  import { Badge } from "src/components/ui/badge";
   6  import { useAlbyMe } from "src/hooks/useAlbyMe";
   7  import { useNodeDetails } from "src/hooks/useNodeDetails";
   8  import { backendTypeConfigs } from "src/lib/backendType";
   9  
  10  import { useInfo } from "src/hooks/useInfo";
  11  
  12  export function About() {
  13    const { data: info } = useInfo();
  14    const { data: albyMe, error: albyMeError } = useAlbyMe();
  15    const lsps2Source = info?.jitChannelsLiquiditySource;
  16    const lsps2Pubkey = lsps2Source?.includes("@")
  17      ? lsps2Source.split("@")[0]
  18      : undefined;
  19    const { data: lsps2NodeDetails } = useNodeDetails(lsps2Pubkey);
  20    const lsps2Label =
  21      lsps2NodeDetails?.alias ||
  22      (lsps2Pubkey ? lsps2Pubkey.slice(0, 8) + "..." : lsps2Source);
  23    const lsps2MinPaymentSizeSat = info?.jitChannelsMinPaymentSizeMsat
  24      ? Math.ceil(info.jitChannelsMinPaymentSizeMsat / 1000)
  25      : undefined;
  26    const lsps2MaxPaymentSizeSat = info?.jitChannelsMaxPaymentSizeMsat
  27      ? Math.floor(info.jitChannelsMaxPaymentSizeMsat / 1000)
  28      : undefined;
  29  
  30    if (!info || (info.albyAccountConnected && !albyMe && !albyMeError)) {
  31      return <Loading />;
  32    }
  33  
  34    const planCode = albyMe?.subscription.plan_code;
  35    let planName: string;
  36    if (planCode?.startsWith("buzz_")) {
  37      planName = "Pro Cloud";
  38    } else if (planCode?.startsWith("pro_")) {
  39      planName = "Pro";
  40    } else if (planCode) {
  41      planName = "Paid";
  42    } else {
  43      planName = "Free";
  44    }
  45  
  46    return (
  47      <>
  48        <SettingsHeader
  49          pageTitle="About"
  50          title="About"
  51          description="Info about your Alby Hub"
  52        />
  53        <div className="grid gap-4">
  54          <div className="grid gap-2">
  55            <p className="font-medium text-sm">Alby Hub Version</p>
  56            <p className="text-muted-foreground text-sm slashed-zero">
  57              {info.version || "dev"}
  58            </p>
  59          </div>
  60          <div className="grid gap-2">
  61            <p className="font-medium text-sm">Lightning Node Backend</p>
  62            <div className="flex items-center gap-2 text-muted-foreground text-sm">
  63              <div className="h-6 w-6">
  64                {backendTypeConfigs[info.backendType].icon}
  65              </div>
  66              <p>{backendTypeConfigs[info.backendType].title}</p>
  67            </div>
  68          </div>
  69          {info.databaseType && (
  70            <div className="grid gap-2">
  71              <p className="font-medium text-sm">Database Storage</p>
  72              <p className="text-muted-foreground text-sm">
  73                {info.databaseType === "postgres"
  74                  ? "PostgreSQL"
  75                  : info.databaseType === "sqlite"
  76                    ? "SQLite"
  77                    : info.databaseType}
  78              </p>
  79            </div>
  80          )}
  81          {info.backendType === "LDK" && (
  82            <div className="grid gap-2">
  83              <p className="font-medium text-sm">VSS</p>
  84              <p className="text-muted-foreground text-sm break-all">
  85                {info.ldkVssEnabled ? `Enabled (${info.ldkVssUrl})` : "Disabled"}
  86              </p>
  87            </div>
  88          )}
  89          {info.chainDataSourceType && (
  90            <div className="grid gap-2">
  91              <p className="font-medium text-sm">Chain Data Source</p>
  92              <div className="flex flex-col gap-1 text-sm text-muted-foreground">
  93                <p className="capitalize">{info.chainDataSourceType}</p>
  94                {info.chainDataSourceAddress && (
  95                  <p className="break-all">{info.chainDataSourceAddress}</p>
  96                )}
  97              </div>
  98            </div>
  99          )}
 100          {info.jitChannelsLiquiditySource && (
 101            <div className="grid gap-2">
 102              <p className="font-medium text-sm">
 103                Just-in-Time channels Liquidity Source LSPS2
 104              </p>
 105              <div className="flex flex-col gap-1 text-sm text-muted-foreground">
 106                {lsps2Pubkey ? (
 107                  <ExternalLink
 108                    to={`${info.mempoolUrl}/lightning/node/${lsps2Pubkey}`}
 109                    className="inline-flex items-center gap-1 underline w-fit"
 110                  >
 111                    {lsps2Label}
 112                    <ExternalLinkIcon className="size-4" />
 113                  </ExternalLink>
 114                ) : (
 115                  <p>{lsps2Label}</p>
 116                )}
 117                <p className="break-all">{info.jitChannelsLiquiditySource}</p>
 118                {(lsps2MinPaymentSizeSat || lsps2MaxPaymentSizeSat) && (
 119                  <p>
 120                    JIT payment size:{" "}
 121                    {lsps2MinPaymentSizeSat
 122                      ? new Intl.NumberFormat().format(lsps2MinPaymentSizeSat)
 123                      : "?"}
 124                    {" - "}
 125                    {lsps2MaxPaymentSizeSat
 126                      ? new Intl.NumberFormat().format(lsps2MaxPaymentSizeSat)
 127                      : "?"}{" "}
 128                    sats
 129                  </p>
 130                )}
 131              </div>
 132            </div>
 133          )}
 134          <div className="grid gap-2">
 135            <p className="font-medium text-sm">Nostr Relays</p>
 136            {info.relays.map((relay) => (
 137              <p className="flex items-center gap-2 text-muted-foreground text-sm">
 138                {relay.url}
 139                <Badge variant={relay.online ? "positive" : "destructive"}>
 140                  {relay.online ? "online" : "offline"}
 141                </Badge>
 142              </p>
 143            ))}
 144          </div>
 145          {info.albyAccountConnected && albyMe && (
 146            <div className="grid gap-2">
 147              <p className="font-medium text-sm">Connected Alby Account</p>
 148              <p className="text-muted-foreground text-sm slashed-zero">
 149                {albyMe.email || albyMe.lightning_address}
 150              </p>
 151            </div>
 152          )}
 153          {info.albyAccountConnected && albyMe?.hub.name && (
 154            <div className="grid gap-2">
 155              <p className="font-medium text-sm">Alby Hub Name</p>
 156              <p className="text-muted-foreground text-sm slashed-zero">
 157                {albyMe.hub.name}
 158              </p>
 159            </div>
 160          )}
 161          {info.albyAccountConnected && (
 162            <div className="grid gap-2">
 163              <p className="font-medium text-sm">Alby Account Plan</p>
 164              <p className="text-muted-foreground text-sm slashed-zero">
 165                {planName}
 166              </p>
 167            </div>
 168          )}
 169        </div>
 170      </>
 171    );
 172  }
 173