IsolatedAppTopupDialog.tsx raw

   1  import React from "react";
   2  import { toast } from "sonner";
   3  import { LoadingButton } from "src/components/ui/custom/loading-button";
   4  import {
   5    Dialog,
   6    DialogContent,
   7    DialogDescription,
   8    DialogFooter,
   9    DialogHeader,
  10    DialogTitle,
  11    DialogTrigger,
  12  } from "src/components/ui/dialog";
  13  import { Input } from "src/components/ui/input";
  14  import { Label } from "src/components/ui/label";
  15  import { useApp } from "src/hooks/useApp";
  16  import { handleRequestError } from "src/utils/handleRequestError";
  17  import { request } from "src/utils/request";
  18  
  19  type IsolatedAppTopupProps = {
  20    appId: number;
  21  };
  22  
  23  export function IsolatedAppTopupDialog({
  24    appId,
  25    children,
  26  }: React.PropsWithChildren<IsolatedAppTopupProps>) {
  27    const { mutate: reloadApp } = useApp(appId);
  28    const [amountSat, setAmountSat] = React.useState("");
  29    const [description, setDescription] = React.useState("");
  30    const [loading, setLoading] = React.useState(false);
  31    const [open, setOpen] = React.useState(false);
  32    async function onSubmit(e: React.FormEvent) {
  33      e.preventDefault();
  34      setLoading(true);
  35      try {
  36        await request(`/api/transfers`, {
  37          method: "POST",
  38          headers: {
  39            "Content-Type": "application/json",
  40          },
  41          body: JSON.stringify({
  42            toAppId: appId,
  43            amountSat: +amountSat,
  44            description,
  45          }),
  46        });
  47        await reloadApp();
  48        toast(`Successfully increased balance by ${+amountSat} sats`);
  49        reset();
  50      } catch (error) {
  51        handleRequestError("Failed to increase sub-wallet balance", error);
  52      }
  53      setLoading(false);
  54    }
  55  
  56    function reset() {
  57      setOpen(false);
  58      setAmountSat("");
  59      setDescription("");
  60    }
  61  
  62    return (
  63      <Dialog open={open} onOpenChange={setOpen}>
  64        <DialogTrigger asChild>{children}</DialogTrigger>
  65        <DialogContent>
  66          <form onSubmit={onSubmit}>
  67            <DialogHeader>
  68              <DialogTitle>Increase Balance</DialogTitle>
  69              <DialogDescription>
  70                Increase the balance of this sub-wallet. Make sure you always
  71                maintain enough funds in your lightning balance to prevent
  72                sub-wallets becoming unspendable.
  73              </DialogDescription>
  74            </DialogHeader>
  75            <div className="grid gap-2 mt-5">
  76              <Label htmlFor="amount">Amount (sats)</Label>
  77              <Input
  78                autoFocus
  79                id="amount"
  80                type="number"
  81                required
  82                value={amountSat}
  83                onChange={(e) => {
  84                  setAmountSat(e.target.value.trim());
  85                }}
  86              />
  87            </div>
  88            <div className="grid gap-2 mt-3">
  89              <Label htmlFor="description">Description (optional)</Label>
  90              <Input
  91                id="description"
  92                type="text"
  93                placeholder="transfer"
  94                value={description}
  95                onChange={(e) => {
  96                  setDescription(e.target.value);
  97                }}
  98              />
  99            </div>
 100            <DialogFooter className="mt-5">
 101              <LoadingButton loading={loading}>Increase</LoadingButton>
 102            </DialogFooter>
 103          </form>
 104        </DialogContent>
 105      </Dialog>
 106    );
 107  }
 108