()
| 79 | }); |
| 80 | |
| 81 | export function NextFlow() { |
| 82 | const [added, setAdded] = useState<readonly Added[]>([]); |
| 83 | const [route, setRoute] = useState<NextRoute>(() => parseRoute(globalThis.location?.hash ?? "")); |
| 84 | |
| 85 | useEffect(() => { |
| 86 | const onHashChange = () => setRoute(parseRoute(globalThis.location?.hash ?? "")); |
| 87 | globalThis.addEventListener("hashchange", onHashChange); |
| 88 | return () => globalThis.removeEventListener("hashchange", onHashChange); |
| 89 | }, []); |
| 90 | |
| 91 | const go = useCallback((next: NextRoute) => { |
| 92 | setRoute(next); |
| 93 | if (globalThis.location) globalThis.location.hash = routeToHash(next); |
| 94 | }, []); |
| 95 | |
| 96 | const addIntegration = useCallback((item: AddedIntegration) => { |
| 97 | setAdded((previous) => |
| 98 | previous.some((entry) => entry.item.domain === item.domain) |
| 99 | ? previous |
| 100 | : [ |
| 101 | ...previous, |
| 102 | // An add always leaves exactly one account behind, already named |
| 103 | // and in the one state that matters. |
| 104 | { item, accounts: [{ label: "default", status: "needs-auth" as const }] }, |
| 105 | ], |
| 106 | ); |
| 107 | }, []); |
| 108 | |
| 109 | const addFromCatalog = useCallback( |
| 110 | (item: CatalogItem) => addIntegration(fromCatalogItem(item)), |
| 111 | [addIntegration], |
| 112 | ); |
| 113 | |
| 114 | const markConnected = useCallback((domain: string, accountLabel: string, identity: string) => { |
| 115 | setAdded((previous) => |
| 116 | previous.map((entry) => |
| 117 | entry.item.domain === domain |
| 118 | ? { |
| 119 | ...entry, |
| 120 | accounts: entry.accounts.map((account) => |
| 121 | account.label === accountLabel |
| 122 | ? { ...account, status: "connected" as const, identity } |
| 123 | : account, |
| 124 | ), |
| 125 | } |
| 126 | : entry, |
| 127 | ), |
| 128 | ); |
| 129 | }, []); |
| 130 | |
| 131 | const activeDomain = route.kind === "detail" || route.kind === "auth" ? route.domain : null; |
| 132 | const open = added.find((entry) => entry.item.domain === activeDomain) ?? null; |
| 133 | const pendingCount = added.filter((entry) => |
| 134 | entry.accounts.some((account) => account.status === "needs-auth"), |
| 135 | ).length; |
| 136 | |
| 137 | // A deep link can name a domain that has not been added in this session. |
| 138 | // Say so rather than rendering an empty detail screen. |
nothing calls this directly
no test coverage detected