1import { useAtomValue } from "@effect/atom-react";
2import { Atom } from "effect/reactivity";
3import * as Linking from "expo-linking";
4import { useEffect } from "react";
5import { Platform } from "react-native";
6import { environmentCatalog } from "../connection/catalog";
7import { environmentPresentations } from "../state/presentation";
8import { publishSubscriptionUsage } from "./publishSubscriptionUsage";
9import { useSubscriptionUsage } from "./useSubscriptionUsage";
10import { buildSubscriptionUsageSnapshot } from "./subscriptionUsageSnapshot";
11
12// Isolate quota changes from the much busier thread/config presentation stream.
13const snapshotAtom = Atom.make((get) =>
14 buildSubscriptionUsageSnapshot(
15 get(environmentPresentations.presentationsAtom),
16 Linking.createURL("settings/usage", { queryParams: { tab: "limits" } }),
17 // Android scrolls the full list; iOS stores a bounded widget timeline.
18 Platform.OS === "android" ? Infinity : 6,
19 ),
20).pipe(Atom.withEquality((a, b) => JSON.stringify(a) === JSON.stringify(b)));
21
22export function SubscriptionUsageCoordinator() {
23 const catalog = useAtomValue(environmentCatalog.catalogValueAtom);
24 const snapshot = useAtomValue(snapshotAtom);
25 useSubscriptionUsage(catalog.isReady);
26 useEffect(() => {
27 if (!catalog.isReady) return;
28 void Promise.resolve()
29 .then(() => publishSubscriptionUsage(snapshot))
30 .catch((error: unknown) => {
31 console.warn("Could not update subscription usage widget", error);
32 });
33 }, [catalog.isReady, snapshot]);
34 return null;
35}