MigrateNode.tsx raw

   1  import { DatabaseIcon, InfoIcon, TriangleAlertIcon } from "lucide-react";
   2  import React, { useState } from "react";
   3  import { useNavigate } from "react-router";
   4  import PasswordInput from "src/components/password/PasswordInput";
   5  
   6  import SettingsHeader from "src/components/SettingsHeader";
   7  import { Button } from "src/components/ui/button";
   8  import { LinkButton } from "src/components/ui/custom/link-button";
   9  import { LoadingButton } from "src/components/ui/custom/loading-button";
  10  import { Label } from "src/components/ui/label";
  11  import {
  12    Tooltip,
  13    TooltipContent,
  14    TooltipProvider,
  15    TooltipTrigger,
  16  } from "src/components/ui/tooltip";
  17  import { useInfo } from "src/hooks/useInfo";
  18  
  19  import { handleRequestError } from "src/utils/handleRequestError";
  20  import { isHttpMode } from "src/utils/isHttpMode";
  21  import { request } from "src/utils/request";
  22  
  23  export function MigrateNode() {
  24    const navigate = useNavigate();
  25    const { data: info } = useInfo();
  26  
  27    const [unlockPassword, setUnlockPassword] = React.useState("");
  28    const [showPasswordScreen, setShowPasswordScreen] = useState<boolean>(false);
  29    const [loading, setLoading] = React.useState(false);
  30  
  31    const onSubmitPassword = async (e: React.FormEvent) => {
  32      e.preventDefault();
  33  
  34      const _isHttpMode = isHttpMode();
  35  
  36      try {
  37        setLoading(true);
  38  
  39        if (_isHttpMode) {
  40          const response = await fetch("/api/backup", {
  41            method: "POST",
  42            headers: {
  43              "Content-Type": "application/json",
  44            },
  45            body: JSON.stringify({
  46              UnlockPassword: unlockPassword,
  47            }),
  48          });
  49  
  50          if (!response.ok) {
  51            throw new Error(await response.text());
  52          }
  53          const blob = await response.blob();
  54          const url = window.URL.createObjectURL(blob);
  55          const a = document.createElement("a");
  56          a.href = url;
  57          a.download = "albyhub.bkp";
  58          document.body.appendChild(a);
  59          a.click();
  60          window.URL.revokeObjectURL(url);
  61          a.remove();
  62        } else {
  63          await request("/api/backup", {
  64            method: "POST",
  65            headers: {
  66              "Content-Type": "application/json",
  67            },
  68            body: JSON.stringify({
  69              unlockPassword,
  70            }),
  71          });
  72        }
  73  
  74        navigate("/create-node-migration-file-success");
  75      } catch (error) {
  76        handleRequestError("Failed to backup the node", error);
  77      } finally {
  78        setLoading(false);
  79      }
  80    };
  81  
  82    return (
  83      <>
  84        <SettingsHeader
  85          title="Migrate Alby Hub"
  86          pageTitle="Migrate"
  87          description="Create migration file in order to move your Alby Hub to another device or server."
  88        />
  89  
  90        <div className="flex flex-col gap-6">
  91          <div className="flex flex-col gap-1">
  92            <div className="flex gap-3 items-center">
  93              <TriangleAlertIcon className="size-4" />
  94              <h3>Do not run your Alby Hub on multiple devices</h3>
  95            </div>
  96            <p className="text-sm ml-7">
  97              After creating this migration file, do not restart Alby Hub on this
  98              device, as this will cause problems and may cause force channel
  99              closures.
 100            </p>
 101          </div>
 102          <div className="flex flex-col gap-1">
 103            <div className="flex gap-3 items-center">
 104              <TriangleAlertIcon className="size-4" />
 105              <h3>Migrate this file only to fresh Alby Hub</h3>
 106            </div>
 107            <p className="text-sm ml-7">
 108              To import the migration file, you must have a brand new Alby Hub on
 109              another device and use the “Advanced” option during the onboarding.
 110            </p>
 111          </div>
 112          <div className="flex flex-col gap-1">
 113            <div className="flex gap-3 items-center">
 114              <TriangleAlertIcon className="size-4" />
 115              <h3>Never share your migration file</h3>
 116            </div>
 117            <p className="text-sm ml-7">
 118              Anyone with this file and your unlock password can access your
 119              funds. Never send it to anyone. Alby support will never ask for it.
 120            </p>
 121          </div>
 122          <div className="flex flex-col gap-1">
 123            <div className="flex gap-3 items-center">
 124              <InfoIcon className="size-4" />
 125              <h3>What happens next?</h3>
 126            </div>
 127            <p className="text-sm ml-7">
 128              After typing your unlock password, you'll be able to download a
 129              migration file which contains a backup of your Alby Hub data. Then
 130              you'll see instructions on how to import this migration file into
 131              another device or server.
 132            </p>
 133          </div>
 134          {info?.databaseType === "postgres" && (
 135            <div className="flex gap-3 items-center">
 136              <DatabaseIcon className="size-4" />
 137              <h3>Your database will be migrated</h3>
 138              <TooltipProvider>
 139                <Tooltip>
 140                  <TooltipTrigger type="button">
 141                    <InfoIcon className="size-4 shrink-0 text-muted-foreground" />
 142                  </TooltipTrigger>
 143                  <TooltipContent className="max-w-xs">
 144                    The contents of your PostgreSQL database will be copied into a
 145                    local SQLite database while the migration file is being
 146                    created. Your new Alby Hub will use this SQLite database.
 147                  </TooltipContent>
 148                </Tooltip>
 149              </TooltipProvider>
 150            </div>
 151          )}
 152        </div>
 153  
 154        {showPasswordScreen ? (
 155          <div>
 156            <h1 className="font-medium mb-1">Enter unlock password</h1>
 157            <p className="text-muted-foreground mb-4">
 158              Your unlock password will be used to encrypt your migration file
 159            </p>
 160            <form
 161              onSubmit={onSubmitPassword}
 162              className="w-full md:w-96 flex flex-col gap-6"
 163            >
 164              <>
 165                <div className="grid gap-2">
 166                  <Label htmlFor="password">Password</Label>
 167                  <PasswordInput
 168                    id="password"
 169                    autoFocus
 170                    onChange={setUnlockPassword}
 171                    value={unlockPassword}
 172                  />
 173                </div>
 174              </>
 175              <LoadingButton loading={loading}>Continue</LoadingButton>
 176            </form>
 177          </div>
 178        ) : (
 179          <div className="flex gap-4">
 180            <Button
 181              type="submit"
 182              disabled={loading}
 183              onClick={() => setShowPasswordScreen(true)}
 184            >
 185              Create Alby Hub Migration File
 186            </Button>
 187  
 188            <LinkButton to="/settings/backup" variant={"secondary"}>
 189              Backup Without Migrating Alby Hub
 190            </LinkButton>
 191          </div>
 192        )}
 193      </>
 194    );
 195  }
 196