refactor: 提取 useShare hook,统一分享和剪贴板逻辑
新增 useShare(Web Share API + clipboard fallback), 消除 QrInviteModal、BlindboxRoomPage、ShareCardModal 三处重复的分享代码。
This commit is contained in:
@@ -7,7 +7,7 @@ import type { SceneType } from "@/types";
|
||||
import { getSceneConfig } from "@/lib/sceneConfig";
|
||||
import Modal from "@/components/Modal";
|
||||
import Button from "@/components/Button";
|
||||
import { useToast } from "@/hooks/useToast";
|
||||
import { useShare } from "@/hooks/useShare";
|
||||
|
||||
interface QrInviteModalProps {
|
||||
open: boolean;
|
||||
@@ -22,40 +22,22 @@ export default function QrInviteModal({
|
||||
roomId,
|
||||
scene = "eat",
|
||||
}: QrInviteModalProps) {
|
||||
const toast = useToast();
|
||||
const { share, copyToClipboard } = useShare();
|
||||
const sceneConfig = getSceneConfig(scene);
|
||||
const inviteUrl =
|
||||
typeof window !== "undefined"
|
||||
? `${window.location.origin}/invite/${roomId}`
|
||||
: "";
|
||||
|
||||
const handleCopy = useCallback(async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(inviteUrl);
|
||||
toast.show("邀请链接已复制,快去发给朋友吧!");
|
||||
} catch {
|
||||
toast.show("复制失败,请手动复制链接");
|
||||
}
|
||||
}, [inviteUrl, toast]);
|
||||
const handleCopy = useCallback(
|
||||
() => copyToClipboard(inviteUrl, "邀请链接已复制,快去发给朋友吧!"),
|
||||
[inviteUrl, copyToClipboard],
|
||||
);
|
||||
|
||||
const handleShare = useCallback(async () => {
|
||||
const shareData = {
|
||||
title: sceneConfig.shareTitle,
|
||||
text: sceneConfig.shareText,
|
||||
url: inviteUrl,
|
||||
};
|
||||
|
||||
try {
|
||||
if (navigator.share && navigator.canShare?.(shareData)) {
|
||||
await navigator.share(shareData);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof Error && e.name === "AbortError") return;
|
||||
}
|
||||
|
||||
handleCopy();
|
||||
}, [inviteUrl, handleCopy, sceneConfig]);
|
||||
const handleShare = useCallback(
|
||||
() => share({ title: sceneConfig.shareTitle, text: sceneConfig.shareText, url: inviteUrl }, handleCopy),
|
||||
[inviteUrl, sceneConfig, share, handleCopy],
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal open={open} onClose={onClose}>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { QRCodeSVG } from "qrcode.react";
|
||||
import { toPng } from "html-to-image";
|
||||
import type { Restaurant, MatchType, SceneType } from "@/types";
|
||||
import { useToast } from "@/hooks/useToast";
|
||||
import { useShare } from "@/hooks/useShare";
|
||||
|
||||
type ShareCardData =
|
||||
| {
|
||||
@@ -832,6 +833,8 @@ export default function ShareCardModal({
|
||||
toast.show("图片已保存");
|
||||
}, [handleGenerate, toast, data]);
|
||||
|
||||
const { share: nativeShare } = useShare();
|
||||
|
||||
const handleShare = useCallback(async () => {
|
||||
const png = await handleGenerate();
|
||||
if (!png) {
|
||||
@@ -840,20 +843,12 @@ export default function ShareCardModal({
|
||||
}
|
||||
|
||||
const file = dataUrlToFile(png, "NoWhatever.png");
|
||||
|
||||
const shareData: ShareData = { files: [file] };
|
||||
try {
|
||||
if (navigator.canShare?.(shareData)) {
|
||||
await navigator.share(shareData);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof Error && e.name === "AbortError") return;
|
||||
const shared = await nativeShare({ files: [file] });
|
||||
if (!shared) {
|
||||
downloadDataUrl(png, "NoWhatever.png");
|
||||
toast.show("图片已保存,快去分享吧!");
|
||||
}
|
||||
|
||||
downloadDataUrl(png, "NoWhatever.png");
|
||||
toast.show("图片已保存,快去分享吧!");
|
||||
}, [handleGenerate, toast]);
|
||||
}, [handleGenerate, toast, nativeShare]);
|
||||
|
||||
const handleBackdropClick = (e: React.MouseEvent) => {
|
||||
if (e.target === backdropRef.current) onClose();
|
||||
|
||||
Reference in New Issue
Block a user