diff --git a/.changeset/seven-ravens-rest.md b/.changeset/seven-ravens-rest.md new file mode 100644 index 000000000000..8a4f89f57f08 --- /dev/null +++ b/.changeset/seven-ravens-rest.md @@ -0,0 +1,5 @@ +--- +"ledger-live-desktop": minor +--- + +LLD: LIVE-15143 use a debounce on the memotag field diff --git a/apps/ledger-live-desktop/src/newArch/features/MemoTag/__tests__/MemoTagField.test.tsx b/apps/ledger-live-desktop/src/newArch/features/MemoTag/__tests__/MemoTagField.test.tsx index 8e75955c2f66..6dc92249e143 100644 --- a/apps/ledger-live-desktop/src/newArch/features/MemoTag/__tests__/MemoTagField.test.tsx +++ b/apps/ledger-live-desktop/src/newArch/features/MemoTag/__tests__/MemoTagField.test.tsx @@ -7,6 +7,14 @@ import { render, screen, fireEvent } from "tests/testUtils"; import MemoTagField from "../components/MemoTagField"; describe("MemoTagField", () => { + beforeAll(() => { + jest.useFakeTimers(); + }); + + afterAll(() => { + jest.useRealTimers(); + }); + it("renders MemoTagField with label and text field", () => { render(); expect(screen.getByText(/Tag \/ Memo/gi)).toBeInTheDocument(); @@ -19,12 +27,14 @@ describe("MemoTagField", () => { expect(screen.queryByText(/Tag \/ Memo/gi)).not.toBeInTheDocument(); }); - it("should call onChange when input value changes", () => { + it("should call onChange when input value changes with a debounce", () => { const handleChange = jest.fn(); render(); fireEvent.change(screen.getByPlaceholderText(/Enter Tag \/ Memo/gi), { target: { value: "new memo" }, }); + expect(handleChange).not.toHaveBeenCalled(); + jest.runAllTimers(); expect(handleChange).toHaveBeenCalledTimes(1); }); diff --git a/apps/ledger-live-desktop/src/newArch/features/MemoTag/components/MemoTagField.tsx b/apps/ledger-live-desktop/src/newArch/features/MemoTag/components/MemoTagField.tsx index a6be608741a6..c54b41585285 100644 --- a/apps/ledger-live-desktop/src/newArch/features/MemoTag/components/MemoTagField.tsx +++ b/apps/ledger-live-desktop/src/newArch/features/MemoTag/components/MemoTagField.tsx @@ -1,12 +1,12 @@ -import React from "react"; +import React, { useState, useEffect } from "react"; import Input, { Props as InputBaseProps } from "~/renderer/components/Input"; +import { useDebounce } from "@ledgerhq/live-common//hooks/useDebounce"; import Label from "~/renderer/components/Label"; import Box from "~/renderer/components/Box"; import { useTranslation } from "react-i18next"; import { Flex, Text, Tooltip } from "@ledgerhq/react-ui"; import styled from "styled-components"; import InfoCircle from "~/renderer/icons/InfoCircle"; - const TooltipContainer = styled(Box)` background-color: ${({ theme }) => theme.colors.palette.neutral.c100}; padding: 10px; @@ -30,6 +30,7 @@ type MemoTagFieldProps = InputBaseProps & { placeholder?: string; label?: string; tooltipText?: string; + validationHandler?: (newValue: string) => string; }; const MemoTagField = ({ @@ -44,8 +45,20 @@ const MemoTagField = ({ placeholder, label, tooltipText, + validationHandler, }: MemoTagFieldProps) => { const { t } = useTranslation(); + const [memoValue, setMemoValue] = useState(value); + const debouncedMemoValue = useDebounce(memoValue, 300); + + useEffect(() => { + if (debouncedMemoValue !== value) onChange?.(debouncedMemoValue || ""); + }, [debouncedMemoValue, onChange, value]); + + const handleChange = (newValue: string) => { + setMemoValue(validationHandler ? validationHandler(newValue) : newValue); + }; + return ( {showLabel && ( @@ -68,10 +81,10 @@ const MemoTagField = ({ {CaracterCountComponent && } { - value = value.replace(/\D/g, ""); if (value !== "") onChange(bridge.updateTransaction(transaction, { transferId: value })); else onChange(bridge.updateTransaction(transaction, { transferId: undefined })); }, @@ -32,6 +31,7 @@ const MemoField = ({ onChange, account, transaction, status, autoFocus }: MemoTa onChange={onTransferIdFieldChange} spellCheck="false" autoFocus={autoFocus} + validationHandler={newValue => newValue.replace(/\D/g, "")} /> ); }; diff --git a/apps/ledger-live-desktop/src/renderer/families/xrp/SendRecipientFields.tsx b/apps/ledger-live-desktop/src/renderer/families/xrp/SendRecipientFields.tsx index 14b073addb19..8c9a3e56239d 100644 --- a/apps/ledger-live-desktop/src/renderer/families/xrp/SendRecipientFields.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/xrp/SendRecipientFields.tsx @@ -15,7 +15,7 @@ const TagField = ({ onChange, account, transaction, autoFocus }: Props) => { const onChangeTag = useCallback( (str: string) => { const bridge = getAccountBridge(account); - const tag = BigNumber(str.replace(/[^0-9]/g, "")); + const tag = BigNumber(str); const patch = { tag: !tag.isNaN() && @@ -37,6 +37,7 @@ const TagField = ({ onChange, account, transaction, autoFocus }: Props) => { value={String(transaction.tag || "")} onChange={onChangeTag} autoFocus={autoFocus} + validationHandler={str => str.replace(/[^0-9]/g, "")} /> ); };