Newer
Older
CrypticOreWallet / src / components / auth / AuthorisedAction.tsx
@Drew Lemmy Drew Lemmy on 8 Mar 2021 2 KB feat: wallet info modal
// Copyright (c) 2020-2021 Drew Lemmy
// This file is part of KristWeb 2 under GPL-3.0.
// Full details: https://github.com/tmpim/KristWeb2/blob/master/LICENSE.txt
import React, { FC, useState } from "react";
import { TooltipPlacement } from "antd/lib/tooltip";

import { useSelector, shallowEqual } from "react-redux";
import { RootState } from "@store";

import { AuthMasterPasswordPopover } from "./AuthMasterPasswordPopover";
import { SetMasterPasswordModal } from "./SetMasterPasswordModal";

import "./AuthorisedAction.less";

import Debug from "debug";
const debug = Debug("kristweb:authorised-action");

interface Props {
  encrypt?: boolean;
  onAuthed?: () => void;
  popoverPlacement?: TooltipPlacement;
  children: React.ReactNode;
}

export const AuthorisedAction: FC<Props> = ({ encrypt, onAuthed, popoverPlacement, children }) => {
  const { isAuthed, hasMasterPassword }
    = useSelector((s: RootState) => s.masterPassword, shallowEqual);

  // Don't render the modal and popover unless we absolutely have to
  const [clicked, setClicked] = useState(false);
  const [modalVisible, setModalVisible] = useState(false);

  // 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;

  if (isAuthed) {
    // The user is authed with their master password, just perform the action
    // directly:
    return React.cloneElement(child, { onClick: (e: MouseEvent) => {
      e.preventDefault();
      debug("authorised action occurred: was already authed");

      if (onAuthed) 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");

        if (!clicked) setClicked(true);
        setModalVisible(true);
      }})}

      {clicked && <SetMasterPasswordModal
        visible={modalVisible}
        onCancel={() => setModalVisible(false)}
        onSubmit={() => {
          debug("authorised action occurred: master password now set, continuing with action");

          setModalVisible(false);
          if (onAuthed) onAuthed();
        }}
      />}
    </>;
  } else {
    // The user has a master password set but is not logged in, prompt them to
    // enter it:
    return <AuthMasterPasswordPopover
      encrypt={encrypt}
      onSubmit={() => {
        debug("authorised action occurred: master password provided");
        if (onAuthed) onAuthed();
      }}
      placement={popoverPlacement}
    >
      {children}
    </AuthMasterPasswordPopover>;
  }
};