Files
calendar/packages/lib/hooks/useCopy.ts
sean-brydonandGitHub e78c8738fb feat: create loading state for copy referral link from dub.co (#16626)
* create loading state for copy referal

* Update packages/features/shell/Shell.tsx
2024-09-14 00:03:05 +09:00

78 lines
2.6 KiB
TypeScript

import { useEffect, useState } from "react";
export function useCopy() {
const [isCopied, setIsCopied] = useState(false);
// eslint-disable-next-line @typescript-eslint/no-empty-function
const noop = () => {};
const copyToClipboard = (
text: string,
options: { onSuccess?: () => void; onFailure?: () => void } = {}
) => {
const { onSuccess = noop, onFailure = noop } = options;
if (typeof navigator !== "undefined" && navigator.clipboard) {
navigator.clipboard
.writeText(text)
.then(() => {
setIsCopied(true);
onSuccess();
})
.catch((error) => {
onFailure();
console.error("Copy to clipboard failed:", error);
});
} else {
console.warn(
"You need to use a secure context to use clipboard \n Please use the following link: ",
text
);
onFailure();
}
};
const resetCopyStatus = () => {
setIsCopied(false);
};
/** @see https://wolfgangrittner.dev/how-to-use-clipboard-api-in-safari/ */
const fetchAndCopyToClipboard = (
promise: Promise<string>,
options: { onSuccess?: () => void; onFailure?: () => void } = {}
) => {
const { onSuccess = noop, onFailure = noop } = options;
if (typeof ClipboardItem && navigator.clipboard?.write) {
// NOTE: Safari locks down the clipboard API to only work when triggered
// by a direct user interaction. You can't use it async in a promise.
// But! You can wrap the promise in a ClipboardItem, and give that to
// the clipboard API.
// Found this on https://developer.apple.com/forums/thread/691873
const text = new ClipboardItem({
"text/plain": promise
.then((text) => new Blob([text], { type: "text/plain" }))
.catch(() => {
onFailure();
return "";
}),
});
navigator.clipboard.write([text]);
onSuccess();
} else {
// NOTE: Firefox has support for ClipboardItem and navigator.clipboard.write,
// but those are behind `dom.events.asyncClipboard.clipboardItem` preference.
// Good news is that other than Safari, Firefox does not care about
// Clipboard API being used async in a Promise.
promise.then((text) => copyToClipboard(text, options)).catch(() => onFailure());
}
};
useEffect(() => {
if (isCopied) {
const timer = setTimeout(resetCopyStatus, 3000); // Reset copy status after 3 seconds
return () => clearTimeout(timer);
}
}, [isCopied]);
return { isCopied, copyToClipboard, resetCopyStatus, fetchAndCopyToClipboard };
}