diff --git a/src/pages/wallets/AddWalletModal.tsx b/src/pages/wallets/AddWalletModal.tsx index 3754f00..621b362 100644 --- a/src/pages/wallets/AddWalletModal.tsx +++ b/src/pages/wallets/AddWalletModal.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2020-2021 Drew Lemmy // This file is part of KristWeb 2 under AGPL-3.0. // Full details: https://github.com/tmpim/KristWeb2/blob/master/LICENSE.txt -import { useState, useRef, useEffect, useCallback } from "react"; +import { useState, useRef, useEffect, useCallback, useMemo } from "react"; import { Modal, Form, Input, Checkbox, Collapse, Button, Tooltip, Typography, Row, Col, message, notification, Grid } from "antd"; import { ReloadOutlined } from "@ant-design/icons"; @@ -21,6 +21,9 @@ useMasterPasswordOnly } from "@wallets"; +import Debug from "debug"; +const debug = Debug("kristweb:add-wallet-modal"); + const { Text } = Typography; const { useBreakpoint } = Grid; @@ -182,6 +185,31 @@ } }, [t, generateNewPassword, updateCalculatedAddress, masterPassword, visible, form, create, editing]); + const initialValues = useMemo(() => ({ + label: editing?.label ?? undefined, + category: editing?.category ?? "", + + username: editing?.username ?? undefined, + + format: editing?.format ?? initialFormat, + save: true + // eslint-disable-next-line react-hooks/exhaustive-deps + }), [ + initialFormat, + editing?.id, + editing?.label, + editing?.category, + editing?.username, + editing?.format + ]); + + // If the `editing` wallet ID changes, refresh the form + useEffect(() => { + if (!form || !editing?.id) return; + form.setFieldsValue(initialValues); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [form, editing?.id]); + return diff --git a/src/pages/wallets/WalletActions.tsx b/src/pages/wallets/WalletActions.tsx index c0491fb..da3e6ff 100644 --- a/src/pages/wallets/WalletActions.tsx +++ b/src/pages/wallets/WalletActions.tsx @@ -2,7 +2,7 @@ // This file is part of KristWeb 2 under AGPL-3.0. // Full details: https://github.com/tmpim/KristWeb2/blob/master/LICENSE.txt import React, { useState } from "react"; -import { Modal, Tooltip, Dropdown, Menu } from "antd"; +import { Modal, Dropdown, Menu } from "antd"; import { MenuClickEventHandler } from "rc-menu/lib/interface"; import { EditOutlined, DeleteOutlined, InfoCircleOutlined, ExclamationCircleOutlined, @@ -11,16 +11,23 @@ import { useTranslation } from "react-i18next"; -import { WalletEditButton } from "./WalletEditButton"; -import { AddWalletModal } from "./AddWalletModal"; +import { AuthorisedAction } from "@comp/auth/AuthorisedAction"; +import { OpenEditWalletFn } from "./WalletEditButton"; import { WalletInfoModal } from "./info/WalletInfoModal"; import { SendTransactionModalLink } from "@comp/transactions/SendTransactionModalLink"; import { Wallet, deleteWallet } from "@wallets"; -export function WalletActions({ wallet }: { wallet: Wallet }): JSX.Element { +interface Props { + wallet: Wallet; + openEditWallet: OpenEditWalletFn; +} + +export function WalletActions({ + wallet, + openEditWallet +}: Props): JSX.Element { const { t } = useTranslation(); - const [editWalletVisible, setEditWalletVisible] = useState(false); const [walletInfoVisible, setWalletInfoVisible] = useState(false); function showWalletDeleteConfirm(): void { @@ -54,14 +61,23 @@ className="table-actions wallet-actions" buttonsRender={([leftButton, rightButton]) => [ - - - {React.cloneElement(leftButton as React.ReactElement, { - className: "ant-btn-left", // force the border-radius - disabled: wallet.dontSave - })} - - , + // Edit wallet button + openEditWallet(wallet)} + popoverPlacement="left" + > + {/* Tooltip was removed for now as an optimisation */} + {/* */} + {React.cloneElement(leftButton as React.ReactElement, { + className: "ant-btn-left", // force the border-radius + disabled: wallet.dontSave + })} + {/* */} + , + + // Dropdown button rightButton ]} @@ -94,7 +110,6 @@ - ; } diff --git a/src/pages/wallets/WalletEditButton.tsx b/src/pages/wallets/WalletEditButton.tsx index 2c423d3..29aae05 100644 --- a/src/pages/wallets/WalletEditButton.tsx +++ b/src/pages/wallets/WalletEditButton.tsx @@ -27,3 +27,29 @@ ; }; + +export type OpenEditWalletFn = (wallet: Wallet) => void; +export type WalletEditHookRes = [ + OpenEditWalletFn, + JSX.Element | null, + (visible: boolean) => void +]; + +export function useEditWalletModal(): WalletEditHookRes { + // The modal will only be rendered if it is opened at least once + const [opened, setOpened] = useState(false); + const [visible, setVisible] = useState(false); + const [wallet, setWallet] = useState(); + + function open(wallet: Wallet) { + setWallet(wallet); + setVisible(true); + if (!opened) setOpened(true); + } + + const modal = opened + ? + : null; + + return [open, modal, setVisible]; +} diff --git a/src/pages/wallets/WalletsPage.tsx b/src/pages/wallets/WalletsPage.tsx index 67b4856..0bcc7e3 100644 --- a/src/pages/wallets/WalletsPage.tsx +++ b/src/pages/wallets/WalletsPage.tsx @@ -15,6 +15,7 @@ import { ManageBackupsDropdown } from "./ManageBackupsDropdown"; import { AddWalletModal } from "./AddWalletModal"; import { WalletsTable } from "./WalletsTable"; +import { useEditWalletModal } from "./WalletEditButton"; /** Extract the subtitle into its own component to avoid re-rendering the * entire page when a wallet is added. */ @@ -56,11 +57,16 @@ } export function WalletsPage(): JSX.Element { + const [openEditWallet, editWalletModal] = useEditWalletModal(); + return } extra={} > - + + + {/* Rendered only once, as an optimisation */} + {editWalletModal} ; } diff --git a/src/pages/wallets/WalletsTable.tsx b/src/pages/wallets/WalletsTable.tsx index 06b2e64..0d3c5a6 100644 --- a/src/pages/wallets/WalletsTable.tsx +++ b/src/pages/wallets/WalletsTable.tsx @@ -11,11 +11,16 @@ import { useWallets } from "@wallets"; import { WalletActions } from "./WalletActions"; +import { OpenEditWalletFn } from "./WalletEditButton"; import { keyedNullSort, localeSort } from "@utils"; import { useDateColumnWidth } from "@utils/table"; -export function WalletsTable(): JSX.Element { +interface Props { + openEditWallet: OpenEditWalletFn; +} + +export function WalletsTable({ openEditWallet }: Props): JSX.Element { const { t } = useTranslation(); const { wallets } = useWallets(); @@ -116,7 +121,12 @@ key: "actions", width: 80, - render: (_, record) => + render: (_, record) => ( + + ) } ]} />;