46 lines
1.8 KiB
TypeScript
46 lines
1.8 KiB
TypeScript
import { useContext } from "react";
|
|
import { QueryClient, QueryClientContext, useQuery } from "@tanstack/react-query";
|
|
import { instanceSettingsApi } from "@/api/instanceSettings";
|
|
import { queryKeys } from "@/lib/queryKeys";
|
|
|
|
/**
|
|
* Fallback client for hosts that render gated components without a
|
|
* QueryClientProvider (isolated unit-test mounts, storybook-style renders).
|
|
* The query is disabled in that case, so this client never fetches — it only
|
|
* keeps `useQuery` from throwing. Created lazily so app code never pays for it.
|
|
*/
|
|
let detachedClient: QueryClient | null = null;
|
|
function getDetachedClient(): QueryClient {
|
|
detachedClient ??= new QueryClient();
|
|
return detachedClient;
|
|
}
|
|
|
|
/**
|
|
* Conference Room Chat experimental flag (PAP-136 / PAP-137).
|
|
*
|
|
* Wraps the shared experimental-settings query so gated call sites don't
|
|
* repeat the boilerplate. `enabled` stays false while the query is in
|
|
* flight (no flash of gated UI, same as the sidebar's `showWorkspacesLink`
|
|
* pattern); `loaded` lets route gates avoid redirecting away before the
|
|
* flag value is actually known.
|
|
*
|
|
* Renders without a QueryClientProvider resolve to the flag-off default
|
|
* (`{ enabled: false, loaded: true }`) instead of throwing, so widely shared
|
|
* leaf components like StatusIcon stay mountable in isolation.
|
|
*/
|
|
export function useConferenceRoomChatEnabled(): { enabled: boolean; loaded: boolean } {
|
|
const contextClient = useContext(QueryClientContext);
|
|
const { data, isFetched } = useQuery(
|
|
{
|
|
queryKey: queryKeys.instance.experimentalSettings,
|
|
queryFn: () => instanceSettingsApi.getExperimental(),
|
|
enabled: contextClient != null,
|
|
},
|
|
contextClient ?? getDetachedClient(),
|
|
);
|
|
if (!contextClient) {
|
|
return { enabled: false, loaded: true };
|
|
}
|
|
return { enabled: data?.enableConferenceRoomChat === true, loaded: isFetched };
|
|
}
|