94 lines
2.8 KiB
TypeScript
94 lines
2.8 KiB
TypeScript
import { Capacitor } from "@capacitor/core";
|
||
import { Share } from "@capacitor/share";
|
||
import { trackEvent } from "../../infra/analytics";
|
||
|
||
export type RecipeShareDeps = Readonly<{
|
||
title: string;
|
||
body: string;
|
||
url: string;
|
||
variantIdForTrack: string;
|
||
strings: { shareCopied: string; shareCopyFailed: string };
|
||
setShareFeedback: (msg: string | null) => void;
|
||
clearShareFeedbackTimer: () => void;
|
||
flashShareFeedback: (message: string) => void;
|
||
}>;
|
||
|
||
/**
|
||
* Partage recette : Share natif (Capacitor / Web Share API) avec repli presse-papiers.
|
||
* Effets de bord analytics conservés ici pour garder l’UI découplée du détail des plateformes.
|
||
*/
|
||
export async function shareRecipeWithFallback(deps: RecipeShareDeps): Promise<void> {
|
||
const trackShareSuccess = () => {
|
||
trackEvent("recipe", "share", deps.variantIdForTrack);
|
||
};
|
||
|
||
if (Capacitor.isNativePlatform()) {
|
||
try {
|
||
await Share.share({
|
||
title: deps.title,
|
||
text: deps.body,
|
||
url: deps.url || undefined,
|
||
dialogTitle: deps.title
|
||
});
|
||
deps.clearShareFeedbackTimer();
|
||
deps.setShareFeedback(null);
|
||
trackShareSuccess();
|
||
return;
|
||
} catch (error: unknown) {
|
||
if (error instanceof DOMException && error.name === "AbortError") return;
|
||
const msg =
|
||
error instanceof Error
|
||
? error.message
|
||
: typeof error === "string"
|
||
? error
|
||
: "";
|
||
if (/cancel/i.test(msg) || msg.toLowerCase().includes("user did not share")) return;
|
||
}
|
||
}
|
||
|
||
const shareWithNative = async () => {
|
||
const basePayload: ShareData = { title: deps.title, text: deps.body };
|
||
if (deps.url) {
|
||
const withUrl: ShareData = { ...basePayload, url: deps.url };
|
||
if (typeof navigator.canShare !== "function" || navigator.canShare(withUrl)) {
|
||
await navigator.share(withUrl);
|
||
return;
|
||
}
|
||
}
|
||
await navigator.share(basePayload);
|
||
};
|
||
|
||
if (typeof navigator.share === "function") {
|
||
try {
|
||
await shareWithNative();
|
||
deps.clearShareFeedbackTimer();
|
||
deps.setShareFeedback(null);
|
||
trackShareSuccess();
|
||
return;
|
||
} catch (error: unknown) {
|
||
const name =
|
||
error instanceof Error || error instanceof DOMException
|
||
? error.name
|
||
: typeof error === "object" &&
|
||
error !== null &&
|
||
"name" in error &&
|
||
typeof (error as { name: unknown }).name === "string"
|
||
? (error as { name: string }).name
|
||
: "";
|
||
if (name === "AbortError") return;
|
||
}
|
||
}
|
||
|
||
try {
|
||
if (navigator.clipboard?.writeText) {
|
||
await navigator.clipboard.writeText(deps.body);
|
||
deps.flashShareFeedback(deps.strings.shareCopied);
|
||
trackShareSuccess();
|
||
} else {
|
||
deps.flashShareFeedback(deps.strings.shareCopyFailed);
|
||
}
|
||
} catch {
|
||
deps.flashShareFeedback(deps.strings.shareCopyFailed);
|
||
}
|
||
}
|