diff --git a/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/ChatPanelElement.tsx b/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/ChatPanelElement.tsx
index 06a8aa9d..8d67e473 100644
--- a/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/ChatPanelElement.tsx
+++ b/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/ChatPanelElement.tsx
@@ -15,10 +15,12 @@ import { NoticeToast, AuthErrorNotice } from './atoms/StatusBanners';
export interface ChatPanelElementProps {
hostElement?: HTMLElement;
+ // Localized label supplied by the Razor host via the element attribute (commonLocalizer).
+ label?: string;
}
-export default function ChatPanelElement({ hostElement }: ChatPanelElementProps) {
- const { available, loaded, connect } = useChatBootstrap();
+export default function ChatPanelElement({ hostElement, label = 'Chat' }: ChatPanelElementProps) {
+ const { available, loaded, loadFailed, reload, connect } = useChatBootstrap();
const channels = useChatStore((state) => state.channels, shallowArrayEqual);
const unread = useChatStore((state) => state.channels.reduce((total, channel) => total + Math.max(0, channel.UnreadCount), 0));
@@ -32,11 +34,17 @@ export default function ChatPanelElement({ hostElement }: ChatPanelElementProps)
const currentUserId = getCurrentUserId();
const activeChannel = channels.find((channel) => channel.ChatChannelId === activeChannelId) ?? null;
+ // Feature-flag gate: the footer button stays hidden until the server confirms the
+ // Chat.System flag is on for this department (GetChannels 404s when it is off).
+ // A non-404 load failure keeps the button visible so the failure view (with its
+ // retry control) stays reachable — only a confirmed flag-off hides chat.
+ const chatVisible = loadFailed || (loaded && available);
+
useEffect(() => {
if (hostElement) {
- hostElement.style.display = loaded && !available ? 'none' : '';
+ hostElement.style.display = chatVisible ? '' : 'none';
}
- }, [hostElement, loaded, available]);
+ }, [hostElement, chatVisible]);
const openPanel = () => {
setOpen(true);
@@ -50,17 +58,19 @@ export default function ChatPanelElement({ hostElement }: ChatPanelElementProps)
setThread(null);
};
- if (loaded && !available) {
+ if (!chatVisible) {
return null;
}
if (!open) {
+ // Collapsed state renders inline inside the site footer (see _Footer.cshtml) so the
+ // button never overlaps page content the way the old floating FAB did.
return (
-
-