();
+
+ const reset = useCallback(() => {
+ form.resetFields();
+ }, [form]);
+
+ const onFinish = useCallback(async function() {
+ const values = await form.validateFields();
+
+ try {
+ await authMasterPassword(salt, tester, values.masterPassword);
+ onSubmit();
+ } catch (err) {
+ setPasswordError(translateError(t, err, tKey("errorUnknown")));
+ }
+ }, [t, tKey, onSubmit, salt, tester, form]);
+
+ const formEl = useMemo(() => <>
+ {tStr(encrypt ? "popoverDescriptionEncrypt" : "popoverDescription")}
+
+
+ {getMasterPasswordInput({
+ inputRef,
+ placeholder: tStr("passwordPlaceholder"),
+ autoFocus: true
+ })}
+
+
+ {/* Fake submit button to allow the enter key to submit in modal */}
+
+
+ >, [tStr, inputRef, encrypt, form, onFinish, passwordError]);
+
+ return { form: formEl, submit: onFinish, reset };
+}
diff --git a/src/components/auth/AuthMasterPasswordModal.tsx b/src/components/auth/AuthMasterPasswordModal.tsx
index 52470eb..cee1512 100644
--- a/src/components/auth/AuthMasterPasswordModal.tsx
+++ b/src/components/auth/AuthMasterPasswordModal.tsx
@@ -6,7 +6,7 @@
import { useTFns } from "@utils/i18n";
-import { useAuthForm } from "./AuthMasterPasswordPopover";
+import { useAuthForm } from "./AuthForm";
interface Props {
visible: boolean;
@@ -24,7 +24,7 @@
const { t, tStr } = useTFns("masterPassword.");
const inputRef = useRef(null);
- const { form, submit, reset } = useAuthForm({ encrypt, onSubmit, inputRef });
+ const { form, submit, reset } = useAuthForm(encrypt, onSubmit, inputRef);
return void;
- placement?: TooltipPlacement;
-}
-
-export const AuthMasterPasswordPopover: FC = ({
- encrypt,
- onSubmit,
- placement,
- children
-}) => {
- const { tStr } = useTFns("masterPassword.");
-
- const inputRef = useRef(null);
-
- const onVisibleChange = useCallback(() =>
- setTimeout(() => inputRef.current?.focus(), 20), [inputRef]);
-
- return }
- >
- {children}
- ;
-};
-
-interface AuthFormProps {
- encrypt?: boolean;
- onSubmit: () => void;
- inputRef: Ref;
-}
-
-function AuthForm({
- encrypt,
- onSubmit,
- inputRef
-}: AuthFormProps): JSX.Element {
- const { tStr } = useTFns("masterPassword.");
-
- const { form, submit } = useAuthForm({ encrypt, onSubmit, inputRef });
-
- return <>
- {form}
-
- {/* Submit button */}
-
- >;
-}
-
-interface AuthFormRes {
- form: JSX.Element;
- submit: () => Promise;
- reset: () => void;
-}
-
-export function useAuthForm({
- encrypt,
- onSubmit,
- inputRef
-}: AuthFormProps): AuthFormRes {
- const { t, tStr, tKey } = useTFns("masterPassword.");
-
- const { salt, tester } = useMasterPassword();
-
- const [form] = Form.useForm();
- const [passwordError, setPasswordError] = useState();
-
- const reset = useCallback(() => {
- form.resetFields();
- }, [form]);
-
- const onFinish = useCallback(async function() {
- const values = await form.validateFields();
-
- try {
- await authMasterPassword(salt, tester, values.masterPassword);
- onSubmit();
- } catch (err) {
- setPasswordError(translateError(t, err, tKey("errorUnknown")));
- }
- }, [t, tKey, onSubmit, salt, tester, form]);
-
- const formEl = useMemo(() => <>
- {tStr(encrypt ? "popoverDescriptionEncrypt" : "popoverDescription")}
-
-
- {getMasterPasswordInput({
- inputRef,
- placeholder: tStr("passwordPlaceholder"),
- autoFocus: true
- })}
-
-
- {/* Fake submit button to allow the enter key to submit in modal */}
-
-
- >, [tStr, inputRef, encrypt, form, onFinish, passwordError]);
-
- return { form: formEl, submit: onFinish, reset };
-}
diff --git a/src/components/auth/AuthorisedAction.less b/src/components/auth/AuthorisedAction.less
deleted file mode 100644
index 72eeb83..0000000
--- a/src/components/auth/AuthorisedAction.less
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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
-.authorised-action-popover {
- width: 320px;
-
- .ant-btn {
- display: block;
- margin-left: auto;
- margin-top: 12px;
- }
-}
diff --git a/src/components/auth/AuthorisedAction.tsx b/src/components/auth/AuthorisedAction.tsx
index 223656a..6093508 100644
--- a/src/components/auth/AuthorisedAction.tsx
+++ b/src/components/auth/AuthorisedAction.tsx
@@ -1,112 +1,41 @@
// 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 React, { FC, useState } from "react";
-import { Grid } from "antd";
-import { TooltipPlacement } from "antd/lib/tooltip";
+import React, { FC, useContext } from "react";
-import { useMasterPassword } from "@wallets";
-import { useBooleanSetting } from "@utils/settings";
+import { useSelector } from "react-redux";
+import { RootState } from "@store";
-import { AuthMasterPasswordPopover } from "./AuthMasterPasswordPopover";
-import { AuthMasterPasswordModal } from "./AuthMasterPasswordModal";
-import { SetMasterPasswordModal } from "./SetMasterPasswordModal";
-
-import "./AuthorisedAction.less";
-
-import Debug from "debug";
-const debug = Debug("kristweb:authorised-action");
+import { AuthContext } from "./AuthContext";
interface Props {
encrypt?: boolean;
onAuthed?: () => void;
- popoverPlacement?: TooltipPlacement;
children: React.ReactNode;
}
-export const AuthorisedAction: FC = ({ encrypt, onAuthed, popoverPlacement, children }) => {
- const { isAuthed, hasMasterPassword } = useMasterPassword();
-
- // Don't render the modal and popover unless we absolutely have to
- const [clicked, setClicked] = useState(false);
- const [modalVisible, setModalVisible] = useState(false);
- const [authModalVisible, setAuthModalVisible] = useState(false);
-
- // Determine whether to use a popover or a modal for auth
- const bps = Grid.useBreakpoint();
- const alwaysModal = useBooleanSetting("modalAuth");
+export const AuthorisedAction: FC = ({ encrypt, onAuthed, children }) => {
+ const isAuthed = useSelector((s: RootState) => s.masterPassword.isAuthed);
+ const promptAuth = useContext(AuthContext);
// This is used to pass the 'onClick' prop down to the child. The child MUST
// support the onClick prop.
// NOTE: If the child is a custom component, make sure it passes `...props`
// down to its child.
- // TODO: Support multiple children?
const child = React.Children.only(children) as React.ReactElement;
+ // Wrap the single child element and override onClick
if (isAuthed) {
- // The user is authed with their master password, just perform the action
- // directly:
+ // Already authed, run onAuthed immediately
return React.cloneElement(child, { onClick: (e: MouseEvent) => {
e.preventDefault();
- debug("authorised action occurred: was already authed");
onAuthed?.();
}});
- } else if (!hasMasterPassword) {
- // The user does not yet have a master password, prompt them to create one:
- return <>
- {React.cloneElement(child, { onClick: (e: MouseEvent) => {
- e.preventDefault();
- debug("authorised action postponed: no master password set");
-
- setClicked(true);
- setModalVisible(true);
- }})}
-
- {clicked && setModalVisible(false)}
- onSubmit={() => {
- debug("authorised action occurred: master password now set, continuing with action");
-
- setModalVisible(false);
- onAuthed?.();
- }}
- />}
- >;
- } else if (!bps.md || alwaysModal) {
- // The user has a master password set but is not logged in, prompt them to
- // enter it. Show a modal on mobile:
- return <>
- {React.cloneElement(child, { onClick: (e: MouseEvent) => {
- e.preventDefault();
- debug("authorised action postponed: no master password set");
-
- setClicked(true);
- setAuthModalVisible(true);
- }})}
-
- {clicked && setAuthModalVisible(false)}
- onSubmit={() => {
- debug("authorised action occurred: master password now set, continuing with action");
-
- setAuthModalVisible(false);
- onAuthed?.();
- }}
- />}
- >;
} else {
- // Show a popover on desktop:
- return {
- debug("authorised action occurred: master password provided");
- onAuthed?.();
- }}
- placement={popoverPlacement}
- >
- {children}
- ;
+ // Not authed, prompt for either set password or auth password
+ return React.cloneElement(child, { onClick: (e: MouseEvent) => {
+ e.preventDefault();
+ promptAuth?.(encrypt, onAuthed);
+ }});
}
};
diff --git a/src/pages/contacts/ContactActions.tsx b/src/pages/contacts/ContactActions.tsx
index 708e763..e29a262 100644
--- a/src/pages/contacts/ContactActions.tsx
+++ b/src/pages/contacts/ContactActions.tsx
@@ -50,7 +50,6 @@
key="leftButton"
encrypt
onAuthed={() => openEditContact(contact)}
- popoverPlacement="left"
>
{React.cloneElement(leftButton as React.ReactElement, {
className: "ant-btn-left"
@@ -69,7 +68,6 @@
openSendTx(undefined, contact.address)}
- popoverPlacement="left"
>
{tStr("actionsSendTransaction")}
diff --git a/src/pages/names/mgmt/NameActions.tsx b/src/pages/names/mgmt/NameActions.tsx
index a861c86..74da6dc 100644
--- a/src/pages/names/mgmt/NameActions.tsx
+++ b/src/pages/names/mgmt/NameActions.tsx
@@ -41,7 +41,6 @@
openSendTx(undefined, nameWithSuffix)}
- popoverPlacement="left"
>
{t("names.actionsTransferKrist")}
@@ -53,7 +52,6 @@
openNameEdit("update", name.name, name.a)}
- popoverPlacement="left"
>
{t("names.actionsUpdateARecord")}
@@ -63,7 +61,6 @@
openNameEdit("transfer", name.name)}
- popoverPlacement="left"
>
{t("names.actionsTransferName")}
@@ -89,7 +86,6 @@
// Send transaction button (not own name)
openSendTx(undefined, nameWithSuffix)}
- popoverPlacement="left"
>
}
settings={[
- booleanSetting("modalAuth"),
booleanSetting("alwaysIncludeMined"),
booleanSetting("copyNameSuffixes"),
booleanSetting("addressCopyButtons"),
diff --git a/src/pages/wallets/WalletActions.tsx b/src/pages/wallets/WalletActions.tsx
index e4a0468..b8f7e97 100644
--- a/src/pages/wallets/WalletActions.tsx
+++ b/src/pages/wallets/WalletActions.tsx
@@ -68,7 +68,6 @@
key="leftButton"
encrypt
onAuthed={() => openEditWallet(wallet)}
- popoverPlacement="left"
>
{/* Tooltip was removed for now as an optimisation */}
{/* */}
@@ -89,10 +88,7 @@