1import { enabledEnvironmentIds } from "@t3tools/client-runtime/state/connections";
2import {
3 createEnvironmentShellAtoms,
4 createEnvironmentShellSummaryAtom,
5 createEnvironmentSnapshotAtom,
6 EMPTY_SHELL_STATE,
7 type EnvironmentShellState,
8} from "@t3tools/client-runtime/state/shell";
9import { useAtomValue } from "@effect/atom-react";
10import type { EnvironmentId } from "@t3tools/contracts";
11import * as Option from "effect/Option";
12import { Atom } from "effect/reactivity";
13
14import { environmentCatalog } from "../connection/catalog";
15import { connectionAtomRuntime } from "../connection/runtime";
16
17export const environmentShell = createEnvironmentShellAtoms(connectionAtomRuntime);
18export const environmentSnapshotAtom = createEnvironmentSnapshotAtom(environmentShell.stateAtom);
19export const environmentShellSummaryAtom = createEnvironmentShellSummaryAtom({
20 catalogValueAtom: environmentCatalog.catalogValueAtom,
21 shellStateValueAtom: environmentShell.stateValueAtom,
22});
23
24const EMPTY_ENVIRONMENT_SHELL_STATE_ATOM = Atom.make<EnvironmentShellState>(EMPTY_SHELL_STATE);
25
26const shellStatus = (state: EnvironmentShellState) => state.status;
27const shellHasError = (state: EnvironmentShellState) => Option.isSome(state.error);
28// The empty placeholder stands until the environment has read its cached shell.
29const shellCacheRead = (state: EnvironmentShellState) => state !== EMPTY_SHELL_STATE;
30
31const shellCacheReadAtom = Atom.family((environmentId: EnvironmentId) =>
32 Atom.make((get) => shellCacheRead(get(environmentShell.stateValueAtom(environmentId)))),
33);
34
35/**
36 * True once every enabled environment has read its cached shell. A list that paints before
37 * then gets the cached rows of one environment at a time.
38 */
39export const shellCachesReadAtom = Atom.make((get) => {
40 const catalog = get(environmentCatalog.catalogValueAtom);
41 if (!catalog.isReady) return false;
42 // Reads every environment, so each one loads its cache now and not after the one before it.
43 let allRead = true;
44 for (const environmentId of enabledEnvironmentIds(catalog)) {
45 if (!get(shellCacheReadAtom(environmentId))) allRead = false;
46 }
47 return allRead;
48}).pipe(Atom.withLabel("mobile-shell-caches-read"));
49
50export function useEnvironmentShellReadiness(environmentId: EnvironmentId | null) {
51 const atom =
52 environmentId === null
53 ? EMPTY_ENVIRONMENT_SHELL_STATE_ATOM
54 : environmentShell.stateValueAtom(environmentId);
55 return {
56 status: useAtomValue(atom, shellStatus),
57 hasError: useAtomValue(atom, shellHasError),
58 cacheRead: useAtomValue(atom, shellCacheRead),
59 };
60}