import { useState } from "react"; import { Alert, type StyleProp } from "react-native"; export function combineStyle( enabled: boolean, fallback: StyleProp, style: StyleProp, ): StyleProp { return enabled ? [fallback, style] : style; } function errorMessage(error: unknown): string { return error instanceof Error ? error.message : "Something went wrong."; } export interface NativeActionDialogMessages { cancel: string; retry: string; } const defaultNativeActionDialogMessages: NativeActionDialogMessages = { cancel: "Cancel", retry: "Retry", }; /** Runs a native UI mutation and offers a single retry action on failure. */ export function useNativeAction( dialogMessages: NativeActionDialogMessages = defaultNativeActionDialogMessages, ) { const [pending, setPending] = useState(false); const run = async ( action: () => Promise, title: string, retryAction: () => Promise = action, ): Promise => { if (pending) return undefined; setPending(true); try { return await action(); } catch (error) { Alert.alert(title, errorMessage(error), [ { text: dialogMessages.cancel, style: "cancel" }, { text: dialogMessages.retry, onPress: () => { void run(retryAction, title, retryAction); }, }, ]); return undefined; } finally { setPending(false); } }; return { pending, run }; }