From 14524df1071cf53d7225bc360e37bb1713492ee6 Mon Sep 17 00:00:00 2001 From: Sim Boon Long Date: Tue, 15 Mar 2022 09:13:50 +0800 Subject: [PATCH] feat: redact text (#85) --- .../common/RedactableValue.stories.tsx | 26 ++++++++ .../common/RedactableValue.test.tsx | 46 +++++++++++++ src/components/common/RedactableValue.tsx | 66 +++++++++++++++++++ src/index.tsx | 1 + 4 files changed, 139 insertions(+) create mode 100644 src/components/common/RedactableValue.stories.tsx create mode 100644 src/components/common/RedactableValue.test.tsx create mode 100644 src/components/common/RedactableValue.tsx diff --git a/src/components/common/RedactableValue.stories.tsx b/src/components/common/RedactableValue.stories.tsx new file mode 100644 index 0000000..e39fda9 --- /dev/null +++ b/src/components/common/RedactableValue.stories.tsx @@ -0,0 +1,26 @@ +import React, { ReactElement } from "react"; +import { RedactableValue } from "./RedactableValue"; + +export default { + title: "RedactableValue/RedactableValue", + component: RedactableValue, +}; + +export const RedactableValueDefault = (): ReactElement => { + return ; +}; + +export const RedactableValueIconDefault = (): ReactElement => { + return console.log("Please redact")} />; +}; + +export const RedactableValueIconCustom = (): ReactElement => { + return ( + console.log("Please redact")} + iconRedact={<>X} + /> + ); +}; diff --git a/src/components/common/RedactableValue.test.tsx b/src/components/common/RedactableValue.test.tsx new file mode 100644 index 0000000..3f519e4 --- /dev/null +++ b/src/components/common/RedactableValue.test.tsx @@ -0,0 +1,46 @@ +import React from "react"; +import { RedactableValue } from "./RedactableValue"; +import { screen, render, fireEvent } from "@testing-library/react"; + +describe("redactablevalue component", () => { + it("should display value only when editable is not set", () => { + const callback = jest.fn(); + render(); + + expect(screen.getByText("Text to display")).toBeInTheDocument(); + expect(screen.queryByTitle("Redact handler")).not.toBeInTheDocument(); + }); + + it("should display value only when editable is set to false", () => { + const callback = jest.fn(); + render(); + + expect(screen.getByText("Text to display")).toBeInTheDocument(); + expect(screen.queryByTitle("Redact handler")).not.toBeInTheDocument(); + }); + + it("should display value, redact default icon and call onRedactionRequested when editable is set to true", () => { + const callback = jest.fn(); + render(); + + expect(screen.getByText("Text to display")).toBeInTheDocument(); + expect(screen.queryByTitle("Redact handler")).toBeInTheDocument(); + expect(screen.queryByTitle("Redact default icon")).toBeInTheDocument(); + fireEvent.click(screen.getByTitle("Redact handler")); + expect(callback).toHaveBeenCalledTimes(1); + }); + + it("should display value, custom icon redact and call onRedactionRequested when editable is set to true", () => { + const callback = jest.fn(); + render( + foobar} /> + ); + + expect(screen.getByText("Text to display")).toBeInTheDocument(); + expect(screen.queryByTitle("Redact handler")).toBeInTheDocument(); + expect(screen.queryByTitle("Redact default icon")).not.toBeInTheDocument(); + expect(screen.getByText("foobar")).toBeInTheDocument(); + fireEvent.click(screen.getByText("foobar")); + expect(callback).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/components/common/RedactableValue.tsx b/src/components/common/RedactableValue.tsx new file mode 100644 index 0000000..aa6883c --- /dev/null +++ b/src/components/common/RedactableValue.tsx @@ -0,0 +1,66 @@ +import React, { FunctionComponent, useState } from "react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faTimes } from "@fortawesome/free-solid-svg-icons"; +import styled from "@emotion/styled"; +import { noop } from "../../utils"; + +const IconRedactStyled = styled.span` + transition: color 0.2s ease-out; + color: #dc2626; // text-red-600 (tailwind) + + &:hover { + color: #b91c1c; // text-red-700 (tailwind) + } +`; + +const IconRedact: FunctionComponent = () => { + return ( + + + + ); +}; + +export interface RedactValueProps { + value?: string | number; + onRedactionRequested?: () => void; + editable?: boolean; + iconRedact?: React.ReactElement; +} + +/** + * RedactableValue component is almost a duplicate of ObfuscatableValue component + * ObfuscatableValue component started from OpenCerts, and may be in use on existing certificates, hence we do not want to meddle with the existing functionality + * RedactableValue component displays a value and a cross when editable props is set to true, allows custom redact icon, hints at redacted values + */ +export const RedactableValue: FunctionComponent = ({ + value, + onRedactionRequested = noop, + editable = false, + iconRedact = , +}) => { + const [isRedacted, setRedacted] = useState(false); + + if (isRedacted) return **Redacted**; + if (!value) return **Field value does not exists**; + + return ( + <> + {value} + {editable && ( + { + if (editable) { + onRedactionRequested(); + setRedacted(true); + } + }} + > + {iconRedact} + + )} + + ); +}; diff --git a/src/index.tsx b/src/index.tsx index f1422de..473a63c 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,5 +1,6 @@ export { FrameConnector } from "./components/frame/FrameConnector"; export { ObfuscatableValue } from "./components/common/ObfuscatableValue"; +export { RedactableValue } from "./components/common/RedactableValue"; export { FramedDocumentRenderer } from "./components/renderer/FramedDocumentRenderer"; export * from "./components/renderer/NoAttachmentRenderer"; export * from "./components/renderer/FullAttachmentRenderer";