1import { useAtomRefresh, useAtomValue } from "@effect/atom-react";
2import * as Cause from "effect/Cause";
3import * as Option from "effect/Option";
4import { AsyncResult, Atom } from "effect/reactivity";
5
6const EMPTY_ASYNC_RESULT_ATOM = Atom.make(AsyncResult.initial<never, never>(false)).pipe(
7 Atom.withLabel("mobile-environment-query:empty"),
8);
9
10export interface EnvironmentQueryView<A> {
11 readonly data: A | null;
12 readonly error: string | null;
13 readonly isPending: boolean;
14 readonly isSuccess: boolean;
15 readonly refresh: () => void;
16}
17
18function formatError(cause: Cause.Cause<unknown>): string {
19 const error = Cause.squash(cause);
20 return error instanceof Error && error.message.trim().length > 0
21 ? error.message
22 : "The environment request failed.";
23}
24
25export function useEnvironmentQuery<A, E>(
26 atom: Atom.Atom<AsyncResult.AsyncResult<A, E>> | null,
27): EnvironmentQueryView<A> {
28 const selectedAtom = atom ?? EMPTY_ASYNC_RESULT_ATOM;
29 const result = useAtomValue(selectedAtom);
30 const refresh = useAtomRefresh(selectedAtom);
31 return {
32 data: Option.getOrNull(AsyncResult.value(result)),
33 error: result._tag === "Failure" ? formatError(result.cause) : null,
34 isPending: atom !== null && result.waiting,
35 isSuccess: result._tag === "Success",
36 refresh,
37 };
38}