Skip to content

Commit

Permalink
feat: redact text (#85)
Browse files Browse the repository at this point in the history
  • Loading branch information
simboonlong authored Mar 15, 2022
1 parent b7b34d0 commit 14524df
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 0 deletions.
26 changes: 26 additions & 0 deletions src/components/common/RedactableValue.stories.tsx
Original file line number Diff line number Diff line change
@@ -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 <RedactableValue value="Some value" />;
};

export const RedactableValueIconDefault = (): ReactElement => {
return <RedactableValue value="Some value" editable onRedactionRequested={() => console.log("Please redact")} />;
};

export const RedactableValueIconCustom = (): ReactElement => {
return (
<RedactableValue
value="Some value"
editable
onRedactionRequested={() => console.log("Please redact")}
iconRedact={<>X</>}
/>
);
};
46 changes: 46 additions & 0 deletions src/components/common/RedactableValue.test.tsx
Original file line number Diff line number Diff line change
@@ -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(<RedactableValue value="Text to display" onRedactionRequested={callback} />);

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(<RedactableValue value="Text to display" onRedactionRequested={callback} editable={false} />);

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(<RedactableValue value="Text to display" onRedactionRequested={callback} editable />);

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(
<RedactableValue value="Text to display" onRedactionRequested={callback} editable iconRedact={<>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);
});
});
66 changes: 66 additions & 0 deletions src/components/common/RedactableValue.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<IconRedactStyled>
<FontAwesomeIcon title="Redact default icon" icon={faTimes} />
</IconRedactStyled>
);
};

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<RedactValueProps> = ({
value,
onRedactionRequested = noop,
editable = false,
iconRedact = <IconRedact />,
}) => {
const [isRedacted, setRedacted] = useState(false);

if (isRedacted) return <span style={{ display: "inline-block", color: "#454B50" }}>**Redacted**</span>;
if (!value) return <span style={{ display: "inline-block", color: "#454B50" }}>**Field value does not exists**</span>;

return (
<>
<span style={{ display: "inline-block", marginRight: "8px" }}>{value}</span>
{editable && (
<span
title="Redact handler"
style={{ display: "inline-block", cursor: "pointer" }}
onClick={() => {
if (editable) {
onRedactionRequested();
setRedacted(true);
}
}}
>
{iconRedact}
</span>
)}
</>
);
};
1 change: 1 addition & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand Down

0 comments on commit 14524df

Please sign in to comment.