diff --git a/src/common/AccountAddress.test.tsx b/src/common/AccountAddress.test.tsx index 1497be8b..17028b67 100644 --- a/src/common/AccountAddress.test.tsx +++ b/src/common/AccountAddress.test.tsx @@ -4,26 +4,30 @@ import { shallowRender } from '../tests'; import AccountAddress from './AccountAddress'; -test("renders", () => { - const result = shallowRender( - - ); - expect(result).toMatchSnapshot(); +describe("AccountAddress", () => { + + it("renders", () => { + const result = shallowRender( + + ); + expect(result).toMatchSnapshot(); + }); + }); diff --git a/src/common/AccountAddress.tsx b/src/common/AccountAddress.tsx index e9f8c2e1..cc621c51 100644 --- a/src/common/AccountAddress.tsx +++ b/src/common/AccountAddress.tsx @@ -1,11 +1,12 @@ import { CoinBalance } from "@logion/node-api"; -import { CSSProperties } from 'react'; +import { CSSProperties, useCallback } from 'react'; import OverlayTrigger from 'react-bootstrap/OverlayTrigger'; import Tooltip from 'react-bootstrap/Tooltip'; import { Account } from './types/Accounts'; import { useCommonContext } from './CommonContext'; import Icon from './Icon'; +import { copyToClipBoard } from "./Tools"; import './AccountAddress.css'; import { Spinner } from "react-bootstrap"; @@ -19,9 +20,17 @@ export interface Props { } export default function AccountAddress(props: Props) { - const { colorTheme } = useCommonContext(); + const { colorTheme, setNotification } = useCommonContext(); - let style: CSSProperties = {}; + const copyAddress = useCallback((e: React.MouseEvent) => { + e.stopPropagation(); + copyToClipBoard(props.account.accountId.address); + setNotification("The address was copied to your clip board"); + }, [ props.account.accountId.address, setNotification ]); + + let style: CSSProperties = { + cursor: "copy" + }; const backgroundIcon = colorTheme.accounts.legalOfficerIcon; let foregroundIcon; if(props.account.isLegalOfficer) { @@ -41,6 +50,7 @@ export default function AccountAddress(props: Props) {
diff --git a/src/common/CommonContext.tsx b/src/common/CommonContext.tsx index 8678040c..744a50a8 100644 --- a/src/common/CommonContext.tsx +++ b/src/common/CommonContext.tsx @@ -37,6 +37,8 @@ export interface CommonContext { expectNewTransactionState: ExpectNewTransactionState; expectNewTransaction: () => void; stopExpectNewTransaction: () => void; + notificationText?: string; + setNotification: (text?: string) => void; } interface FullCommonContext extends CommonContext { @@ -83,6 +85,7 @@ function initialContextValue(): FullCommonContext { }, expectNewTransaction: () => {}, stopExpectNewTransaction: () => {}, + setNotification: () => {}, } } @@ -106,6 +109,8 @@ type ActionType = 'FETCH_IN_PROGRESS' | 'SET_EXPECT_NEW_TRANSACTION' | 'STOP_EXPECT_NEW_TRANSACTION' | 'SET_STOP_EXPECT_NEW_TRANSACTION' + | 'SET_NOTIFICATION' + | 'SET_SET_NOTIFICATION' ; interface Action { @@ -128,6 +133,8 @@ interface Action { backendConfig?: ((legalOfficerAddress: string | undefined) => BackendConfig); expectNewTransaction?: () => void; stopExpectNewTransaction?: () => void; + notificationText?: string; + setNotification?: (text?: string) => void; } const MAX_REFRESH_COUNT = 12; @@ -239,6 +246,18 @@ const reducer: Reducer = (state: FullCommonContext, a refreshCount: 0, }, }; + case "SET_NOTIFICATION": { + return { + ...state, + notificationText: action.notificationText, + }; + } + case "SET_SET_NOTIFICATION": { + return { + ...state, + setNotification: action.setNotification!, + }; + } default: /* istanbul ignore next */ throw new Error(`Unknown type: ${action.type}`); @@ -422,6 +441,22 @@ export function CommonContextProvider(props: Props) { } }, [ contextValue.stopExpectNewTransaction, stopExpectNewTransaction ]); + const setNotification = useCallback((text?: string) => { + dispatch({ + type: "SET_NOTIFICATION", + notificationText: text, + }); + }, [ ]); + + useEffect(() => { + if(contextValue.setNotification !== setNotification) { + dispatch({ + type: "SET_SET_NOTIFICATION", + setNotification, + }) + } + }, [ contextValue.setNotification, setNotification ]); + return ( {props.children} diff --git a/src/common/CopyPasteButton.tsx b/src/common/CopyPasteButton.tsx index 1354cc99..51da993a 100644 --- a/src/common/CopyPasteButton.tsx +++ b/src/common/CopyPasteButton.tsx @@ -1,3 +1,4 @@ +import { useCallback } from "react"; import Button from "./Button"; import Icon from "./Icon"; import { copyToClipBoard } from "./Tools"; @@ -5,6 +6,7 @@ import { copyToClipBoard } from "./Tools"; import './CopyPasteButton.css'; import { customClassName } from "./types/Helpers"; import { OverlayTrigger, Tooltip } from "react-bootstrap"; +import { useCommonContext } from "./CommonContext"; export interface Props { value?: string | null; @@ -13,7 +15,15 @@ export interface Props { } export default function CopyPasteButton(props: Props) { + const { setNotification } = useCommonContext(); + + const copy = useCallback(() => { + copyToClipBoard(props.value || ""); + setNotification("Value was copied to the clip board"); + }, [ props.value, setNotification ]); + const value = props.value; + const className = customClassName("CopyPasteButton", props.className ? props.className : "big"); if(value) { if(props.tooltip) { return ( @@ -27,23 +37,20 @@ export default function CopyPasteButton(props: Props) { } > - { renderButton(props) } + ); } else { - return renderButton(props); + return ( + + ); } } else { return null; } } - -function renderButton(props: Props) { - const className = customClassName("CopyPasteButton", props.className ? props.className : "big"); - return ( - - ); -} diff --git a/src/common/Dashboard.css b/src/common/Dashboard.css index 37185d54..fe899c41 100644 --- a/src/common/Dashboard.css +++ b/src/common/Dashboard.css @@ -157,6 +157,13 @@ padding-bottom: 30px; } +.Dashboard .Notifications { + position: absolute; + top: 130px; + right: 35px; + width: 280px; +} + @media (max-width: 1350px) { .Dashboard .Sidebar { width: 260px; diff --git a/src/common/Dashboard.tsx b/src/common/Dashboard.tsx index 63d45bc2..5b6654dd 100644 --- a/src/common/Dashboard.tsx +++ b/src/common/Dashboard.tsx @@ -1,5 +1,6 @@ import Row from 'react-bootstrap/Row'; import Col from 'react-bootstrap/Col'; +import Toast from 'react-bootstrap/Toast'; import { Children } from './types/Helpers'; import Logo from './Logo'; @@ -159,7 +160,7 @@ export interface Props { } export default function Dashboard(props: Props) { - const { colorTheme } = useCommonContext(); + const { colorTheme, notificationText, setNotification } = useCommonContext(); const inlineCss = ` .Dashboard .PrimaryArea .table { @@ -215,6 +216,17 @@ export default function Dashboard(props: Props) { { props.children } +
+ setNotification(undefined) } + bg={ colorTheme.type } + autohide + delay={ 3000 } + > + { notificationText } + +
); } diff --git a/src/common/__snapshots__/AccountAddress.test.tsx.snap b/src/common/__snapshots__/AccountAddress.test.tsx.snap index c3614e6d..6a4b4f58 100644 --- a/src/common/__snapshots__/AccountAddress.test.tsx.snap +++ b/src/common/__snapshots__/AccountAddress.test.tsx.snap @@ -1,14 +1,16 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`renders 1`] = ` +exports[`AccountAddress renders 1`] = `
diff --git a/src/common/__snapshots__/Dashboard.test.tsx.snap b/src/common/__snapshots__/Dashboard.test.tsx.snap index 5675d734..da466ce8 100644 --- a/src/common/__snapshots__/Dashboard.test.tsx.snap +++ b/src/common/__snapshots__/Dashboard.test.tsx.snap @@ -56,6 +56,19 @@ exports[`renders Dashboard 1`] = ` />
+
+ + + +
`;