first commit
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user