From cad74236c1de98e929a32644a3b182b8f9b72d59 Mon Sep 17 00:00:00 2001 From: Siarhei Dudko Date: Tue, 27 Feb 2024 02:19:01 +0400 Subject: [PATCH] fix useCallable hook --- src/methods/ping.tsx | 25 ++-------------- src/utils/getErrorFromCallable.ts | 7 +++++ src/utils/useCallableFn.ts | 50 +++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 23 deletions(-) create mode 100644 src/utils/getErrorFromCallable.ts create mode 100644 src/utils/useCallableFn.ts diff --git a/src/methods/ping.tsx b/src/methods/ping.tsx index 161fe95..56c383e 100644 --- a/src/methods/ping.tsx +++ b/src/methods/ping.tsx @@ -1,6 +1,5 @@ import { HttpsCallableResult } from "firebase/functions"; -import { useHttpsCallable } from "react-firebase-hooks/functions"; -import FirebaseFunctions from "../services/FirebaseFunctions"; +import { useCallableFn } from "../utils/useCallableFn"; const methodName = "v1_ping" as const; @@ -10,24 +9,4 @@ export type PingData = { scope?: string[]; }; -type PingDataRun = (data: { - action: typeof methodName; - data: PingData; -}) => Promise; - -export type Ping = Readonly< - [run: (data: PingData) => Promise, progress: boolean, err?: Error] ->; - -export const usePing = (): Ping => { - const orig = useHttpsCallable(FirebaseFunctions, "app"); - return [ - (data: PingData) => - (orig[0] as PingDataRun)({ - action: methodName, - data, - }), - orig[1], - orig[2], - ]; -}; +export const usePing = () => useCallableFn(methodName); diff --git a/src/utils/getErrorFromCallable.ts b/src/utils/getErrorFromCallable.ts new file mode 100644 index 0000000..2d6b43c --- /dev/null +++ b/src/utils/getErrorFromCallable.ts @@ -0,0 +1,7 @@ +export const getErrorFromCallable = (err: Error | any): Error => { + return new Error( + (err as any)?.details?.details || + (err as any)?.details?.message || + "Unknown error" + ); +}; diff --git a/src/utils/useCallableFn.ts b/src/utils/useCallableFn.ts new file mode 100644 index 0000000..d3942fb --- /dev/null +++ b/src/utils/useCallableFn.ts @@ -0,0 +1,50 @@ +import { useState } from "react"; +import FirebaseFunctions from "../services/FirebaseFunctions"; +import { HttpsCallableResult, httpsCallable } from "firebase/functions"; +import { getErrorFromCallable } from "./getErrorFromCallable"; + +export const useCallableFn = ( + methodName: string +): Readonly<[run: (data: T) => Promise, progress: boolean, err?: Error]> => { + const appFn: (data: { + action: string; + data: T; + }) => Promise> = httpsCallable< + { action: string; data: T }, + K + >(FirebaseFunctions, "app"); + const resp: { + result?: K; + progress: boolean; + error?: Error; + } = { + progress: false, + }; + const [, setProgress] = useState(false); + return [ + async (data: T) => { + resp.result = undefined; + resp.progress = true; + resp.error = undefined; + setProgress(true); + return appFn({ action: methodName, data }) + .then((res) => { + resp.result = res.data; + resp.progress = false; + resp.error = undefined; + return Promise.resolve(resp.result); + }) + .catch((error) => { + resp.result = undefined; + resp.progress = false; + resp.error = getErrorFromCallable(error); + return Promise.reject(resp.error); + }) + .finally(() => { + setProgress(false); + }); + }, + resp.progress, + resp.error, + ]; +};