| 1 | import { useAtomRefresh, useAtomValue } from "@effect/atom-react"; |
| 2 | import * as Cause from "effect/Cause"; |
| 3 | import * as Option from "effect/Option"; |
| 4 | import { AsyncResult, Atom } from "effect/reactivity"; |
| 5 | |
| 6 | const EMPTY_ASYNC_RESULT_ATOM = Atom.make(AsyncResult.initial<never, never>(false)).pipe( |
| 7 | Atom.withLabel("mobile-environment-query:empty"), |
| 8 | ); |
| 9 | |
| 10 | export 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 | |
| 18 | function 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 | |
| 25 | export 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 | } |