Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add user feedback for copy button #516

Merged
merged 6 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/components/CopyButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { BiRegularCopy } from "solid-icons/bi";
import { IoCheckmark } from "solid-icons/io";
import { Show, createSignal } from "solid-js";

import { useGlobalContext } from "../context/Global";
import { clipboard } from "../utils/helper";

const CopyButton = ({ data, label }) => {
const { t } = useGlobalContext();
const [buttonClass, setButtonClass] = createSignal<string>("btn");
const [buttonActive, setButtonActive] = createSignal<boolean>(false);
const onClick = () => {
clipboard(data);
setButtonClass("btn btn-active");
setButtonActive(true);
setTimeout(() => {
setButtonClass("btn");
setButtonActive(false);
}, 600);
};

return (
<span class={buttonClass()} onClick={onClick}>
<Show
when={buttonActive() === true}
fallback=<BiRegularCopy size={21} />>
<IoCheckmark size={21} />
</Show>
{t(label)}
</span>
);
};

export default CopyButton;
38 changes: 19 additions & 19 deletions src/i18n/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ const dict = {
invalid_invoice:
"Please provide a valid LN invoice, LNAddress or LNURL",
invalid_0_amount: "Invoices without amount are not supported",
copy_invoice: "Copy lightning invoice",
copy_address: "Copy address",
copy_amount: "Copy amount",
copy_bip21: "Copy BIP21",
copied: "Copied to clipboard!",
copy_invoice: "lightning invoice",
copy_address: "address",
copy_amount: "amount",
copy_bip21: "BIP21",
copied: "Copied!",
backup_skip: "Skip download",
backup_refund: "Download Refund File",
backup_refund_subline:
Expand Down Expand Up @@ -257,11 +257,11 @@ const dict = {
invalid_backup_file: "Ungültige Backupdatei",
invalid_invoice: "Bitte gültige Rechnung, LNAdresse/LNURL eingeben",
invalid_0_amount: "Lightning Rechnungen ohne Betrag nicht unterstützt",
copy_invoice: "Lightning-Rechnung kopieren",
copy_address: "Adresse kopieren",
copy_amount: "Betrag kopieren",
copy_bip21: "BIP21 kopieren",
copied: "In die Zwischenablage kopiert!",
copy_invoice: "Lightning-Rechnung",
copy_address: "Adresse",
copy_amount: "Betrag",
copy_bip21: "BIP21",
copied: "kopiert!",
backup_skip: "Überspringen",
backup_refund: "Rückerstattungsdatei herunterladen",
backup_refund_subline:
Expand Down Expand Up @@ -439,10 +439,10 @@ const dict = {
invalid_backup_file: "Archivo de backup no válido",
invalid_invoice: "Por favor, pegue una factura, LNAddress/LNURL válida",
invalid_0_amount: "No se admiten facturas sin importe",
copy_invoice: "Copiar factura Lightning",
copy_address: "Copiar dirección",
copy_amount: "Copiar importe",
copy_bip21: "Copiar BIP21",
copy_invoice: "factura Lightning",
copy_address: "dirección",
copy_amount: "importe",
copy_bip21: "BIP21",
copied: "Copiado",
backup_skip: "Saltar",
backup_refund: "Descargar archivo de reembolso",
Expand Down Expand Up @@ -620,11 +620,11 @@ const dict = {
invalid_backup_file: "无效的备份文件",
invalid_invoice: "请提供有效的闪电网络发票、LNAddress或LNURL",
invalid_0_amount: "不支持没有金额的发票",
copy_invoice: "复制闪电网络发票",
copy_address: "复制地址",
copy_amount: "复制金额",
copy_bip21: "复制BIP21",
copied: "已复制到剪贴板!",
copy_invoice: "闪电网络发票",
copy_address: "地址",
copy_amount: "金额",
copy_bip21: "BIP21",
copied: "已复制",
backup_skip: "跳过下载",
backup_refund: "下载退款文件",
backup_refund_subline:
Expand Down
28 changes: 10 additions & 18 deletions src/status/InvoiceSet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { BigNumber } from "bignumber.js";
import { Show } from "solid-js";

import ContractTransaction from "../components/ContractTransaction";
import CopyButton from "../components/CopyButton";
import QrCode from "../components/QrCode";
import { BTC, RBTC } from "../consts";
import { useCreateContext } from "../context/Create";
Expand Down Expand Up @@ -86,24 +87,15 @@ const InvoiceSet = () => {
</Show>
<hr />
<div class="btns">
<span
class="btn"
onclick={() =>
clipboard(
formatAmount(
BigNumber(swap().expectedAmount),
denomination(),
),
)
}>
{t("copy_amount")}
</span>
<span class="btn" onclick={() => clipboard(swap().address)}>
{t("copy_address")}
</span>
<span class="btn" onclick={() => clipboard(swap().bip21)}>
{t("copy_bip21")}
</span>
<CopyButton
label="copy_amount"
data={formatAmount(
BigNumber(swap().expectedAmount),
denomination(),
)}
/>
<CopyButton label="copy_address" data={swap().address} />
<CopyButton label="copy_bip21" data={swap().bip21} />
</div>
</div>
);
Expand Down
5 changes: 2 additions & 3 deletions src/status/SwapCreated.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { BigNumber } from "bignumber.js";
import log from "loglevel";
import { Show } from "solid-js";

import CopyButton from "../components/CopyButton";
import QrCode from "../components/QrCode";
import { BTC } from "../consts";
import { useGlobalContext } from "../context/Global";
Expand Down Expand Up @@ -59,9 +60,7 @@ const SwapCreated = () => {
</a>
</Show>
<hr class="spacer" />
<span class="btn" onclick={() => clipboard(swap().invoice)}>
{t("copy_invoice")}
</span>
<CopyButton label="copy_invoice" data={swap().invoice} />
</div>
);
};
Expand Down
8 changes: 6 additions & 2 deletions src/style/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ hr.spacer {

.btn {
cursor: pointer;
display: block;
margin-top: 10px;
padding: 8px 12px;
text-decoration: none;
Expand All @@ -146,6 +145,11 @@ hr.spacer {
text-transform: uppercase;
border: none;
width: 100%;
display: flex;
justify-content: center;
svg {
margin-right: 3px;
}
}

.btn-small {
Expand Down Expand Up @@ -185,6 +189,7 @@ hr.spacer {
cursor: not-allowed;
}

.btn-active,
.btn-small:hover,
.btn:hover,
.tag .btn:hover {
Expand Down Expand Up @@ -232,7 +237,6 @@ hr.spacer {
justify-content: space-between;
}
.btns .btn {
display: inline-block;
width: auto;
margin: 3px;
flex-grow: 1;
Expand Down
35 changes: 35 additions & 0 deletions tests/components/CopyButton.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { fireEvent, render } from "@solidjs/testing-library";

import CopyButton from "../../src/components/CopyButton";
import i18n from "../../src/i18n/i18n";
import { contextWrapper } from "../helper";

const writeText = jest.fn();

Object.defineProperty(navigator, "clipboard", {
value: {
writeText,
},
});

describe("CopyButton", () => {
test("should stay active for 1 second and copy into clipboard", async () => {
const textToCopy = "clipboard";

const {
container: { firstChild: button },
} = render(() => <CopyButton label="copy_bip21" data={textToCopy} />, {
wrapper: contextWrapper,
});

let btn = button as HTMLSpanElement;

expect(btn).not.toBeUndefined();
expect(btn.textContent).toEqual(i18n.en.copy_bip21);
fireEvent.click(btn);
expect(btn.classList.contains("btn-active")).toBeTruthy();
await new Promise((resolve) => setTimeout(resolve, 700));
expect(btn.classList.contains("btn-active")).toBeFalsy();
expect(navigator.clipboard.writeText).toHaveBeenCalledWith(textToCopy);
});
});
Loading