@djangocfg/layouts 2.1.226 → 2.1.228
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -17
- package/package.json +18 -18
- package/src/components/errors/ErrorLayout.tsx +2 -2
- package/src/components/errors/ErrorsTracker/index.ts +1 -0
- package/src/components/errors/ErrorsTracker/utils/formatters.ts +23 -1
- package/src/hooks/useLogout.ts +9 -12
- package/src/layouts/AppLayout/AppLayout.tsx +20 -8
- package/src/layouts/AppLayout/BaseApp.tsx +5 -28
- package/src/layouts/AuthLayout/AuthLayout.tsx +51 -22
- package/src/layouts/AuthLayout/README.md +78 -0
- package/src/layouts/AuthLayout/components/shared/AuthDivider.tsx +2 -2
- package/src/layouts/AuthLayout/components/shared/AuthError.tsx +10 -2
- package/src/layouts/AuthLayout/components/shared/AuthFooter.tsx +2 -2
- package/src/layouts/AuthLayout/components/shared/AuthHeader.tsx +3 -2
- package/src/layouts/AuthLayout/components/shared/AuthOTPInput.tsx +4 -1
- package/src/layouts/AuthLayout/components/shared/TermsCheckbox.tsx +2 -2
- package/src/layouts/AuthLayout/components/shared/index.ts +0 -2
- package/src/layouts/AuthLayout/components/steps/IdentifierStep.tsx +25 -80
- package/src/layouts/AuthLayout/components/steps/OTPStep.tsx +8 -13
- package/src/layouts/AuthLayout/components/steps/SetupStep/SetupComplete.tsx +2 -2
- package/src/layouts/AuthLayout/components/steps/SetupStep/SetupLoading.tsx +2 -2
- package/src/layouts/AuthLayout/components/steps/SetupStep/SetupQRCode.tsx +2 -2
- package/src/layouts/AuthLayout/components/steps/TwoFactorStep.tsx +61 -42
- package/src/layouts/AuthLayout/context.tsx +0 -2
- package/src/layouts/AuthLayout/index.ts +9 -6
- package/src/layouts/AuthLayout/styles/auth.css +265 -120
- package/src/layouts/AuthLayout/types.ts +60 -7
- package/src/layouts/ProfileLayout/.claude/.sidecar/activity.jsonl +2 -0
- package/src/layouts/ProfileLayout/.claude/.sidecar/history/2026-03-15.md +35 -0
- package/src/layouts/ProfileLayout/.claude/.sidecar/review.md +35 -0
- package/src/layouts/ProfileLayout/.claude/.sidecar/scan.log +3 -0
- package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-001.md +18 -0
- package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-002.md +19 -0
- package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-003.md +18 -0
- package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-004.md +18 -0
- package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-005.md +18 -0
- package/src/layouts/ProfileLayout/.claude/.sidecar/usage.json +5 -0
- package/src/layouts/ProfileLayout/ProfileLayout.tsx +52 -403
- package/src/layouts/ProfileLayout/components/ActionButton.tsx +38 -0
- package/src/layouts/ProfileLayout/components/DeleteAccountSection.tsx +109 -148
- package/src/layouts/ProfileLayout/components/EditableField.tsx +119 -0
- package/src/layouts/ProfileLayout/components/Section.tsx +22 -0
- package/src/layouts/ProfileLayout/components/index.ts +4 -1
- package/src/layouts/ProfileLayout/context.tsx +31 -0
- package/src/layouts/PublicLayout/components/PublicMobileDrawer.tsx +2 -2
- package/src/layouts/PublicLayout/components/PublicNavigation.tsx +2 -2
- package/src/layouts/_components/UserMenu.tsx +2 -2
- package/src/layouts/types/README.md +0 -20
- package/src/layouts/types/index.ts +2 -2
- package/src/layouts/types/layout.types.ts +2 -5
- package/src/layouts/types/providers.types.ts +0 -27
- package/src/snippets/AuthDialog/AuthDialog.tsx +2 -2
- package/src/snippets/Breadcrumbs.tsx +2 -2
- package/src/snippets/index.ts +0 -67
- package/src/layouts/AuthLayout/components/shared/ChannelToggle.tsx +0 -56
- package/src/snippets/McpChat/README.md +0 -441
- package/src/snippets/McpChat/components/AIChatWidget.tsx +0 -361
- package/src/snippets/McpChat/components/AskAIButton.tsx +0 -92
- package/src/snippets/McpChat/components/ChatMessages.tsx +0 -138
- package/src/snippets/McpChat/components/ChatPanel.tsx +0 -131
- package/src/snippets/McpChat/components/ChatSidebar.tsx +0 -156
- package/src/snippets/McpChat/components/ChatWidget.tsx +0 -115
- package/src/snippets/McpChat/components/MessageBubble.tsx +0 -142
- package/src/snippets/McpChat/components/MessageInput.tsx +0 -140
- package/src/snippets/McpChat/components/index.ts +0 -24
- package/src/snippets/McpChat/config.ts +0 -94
- package/src/snippets/McpChat/context/AIChatContext.tsx +0 -327
- package/src/snippets/McpChat/context/ChatContext.tsx +0 -361
- package/src/snippets/McpChat/context/index.ts +0 -7
- package/src/snippets/McpChat/hooks/index.ts +0 -6
- package/src/snippets/McpChat/hooks/useAIChat.ts +0 -503
- package/src/snippets/McpChat/hooks/useChatLayout.ts +0 -442
- package/src/snippets/McpChat/hooks/useMcpChat.ts +0 -90
- package/src/snippets/McpChat/index.ts +0 -79
- package/src/snippets/McpChat/types.ts +0 -189
- package/src/snippets/PWAInstall/@docs/README.md +0 -92
- package/src/snippets/PWAInstall/@docs/research/ios-android-install-flows.md +0 -576
- package/src/snippets/PWAInstall/README.md +0 -235
- package/src/snippets/PWAInstall/components/A2HSHint.tsx +0 -236
- package/src/snippets/PWAInstall/components/DesktopGuide.tsx +0 -234
- package/src/snippets/PWAInstall/components/IOSGuide.tsx +0 -29
- package/src/snippets/PWAInstall/components/IOSGuideDrawer.tsx +0 -103
- package/src/snippets/PWAInstall/components/IOSGuideModal.tsx +0 -103
- package/src/snippets/PWAInstall/components/PWAPageResumeManager.tsx +0 -33
- package/src/snippets/PWAInstall/context/InstallContext.tsx +0 -102
- package/src/snippets/PWAInstall/hooks/useInstallPrompt.ts +0 -168
- package/src/snippets/PWAInstall/hooks/useIsPWA.ts +0 -116
- package/src/snippets/PWAInstall/hooks/usePWAPageResume.ts +0 -163
- package/src/snippets/PWAInstall/index.ts +0 -80
- package/src/snippets/PWAInstall/types/components.ts +0 -95
- package/src/snippets/PWAInstall/types/config.ts +0 -29
- package/src/snippets/PWAInstall/types/index.ts +0 -26
- package/src/snippets/PWAInstall/types/install.ts +0 -38
- package/src/snippets/PWAInstall/types/platform.ts +0 -29
- package/src/snippets/PWAInstall/utils/localStorage.ts +0 -181
- package/src/snippets/PWAInstall/utils/logger.ts +0 -149
- package/src/snippets/PWAInstall/utils/platform.ts +0 -151
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
export { ChatWidget } from './ChatWidget';
|
|
4
|
-
export type { ChatWidgetProps } from './ChatWidget';
|
|
5
|
-
|
|
6
|
-
export { AIChatWidget } from './AIChatWidget';
|
|
7
|
-
export type { AIChatWidgetProps } from './AIChatWidget';
|
|
8
|
-
|
|
9
|
-
export { ChatPanel } from './ChatPanel';
|
|
10
|
-
|
|
11
|
-
export { ChatMessages } from './ChatMessages';
|
|
12
|
-
export type { ChatMessagesProps, ChatMessagesHandle } from './ChatMessages';
|
|
13
|
-
|
|
14
|
-
export { MessageBubble } from './MessageBubble';
|
|
15
|
-
export type { MessageBubbleProps } from './MessageBubble';
|
|
16
|
-
|
|
17
|
-
export { AIMessageInput } from './MessageInput';
|
|
18
|
-
export type { AIMessageInputProps } from './MessageInput';
|
|
19
|
-
|
|
20
|
-
export { ChatSidebar } from './ChatSidebar';
|
|
21
|
-
export type { ChatSidebarProps } from './ChatSidebar';
|
|
22
|
-
|
|
23
|
-
export { AskAIButton } from './AskAIButton';
|
|
24
|
-
export type { AskAIButtonProps } from './AskAIButton';
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* McpChat configuration
|
|
3
|
-
* Environment-aware configuration for MCP server endpoints
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// Hosts
|
|
7
|
-
const PROD_HOST = 'https://mcp.djangocfg.com';
|
|
8
|
-
const DEV_HOST = 'http://localhost:3002';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Get host based on auto-detect flag
|
|
12
|
-
* @param autoDetect - If true, auto-detect based on NODE_ENV. If false, always use PROD_HOST
|
|
13
|
-
*/
|
|
14
|
-
function getHost(autoDetect: boolean = false): string {
|
|
15
|
-
if (autoDetect && process.env.NODE_ENV === 'development') {
|
|
16
|
-
return DEV_HOST;
|
|
17
|
-
}
|
|
18
|
-
return PROD_HOST;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Get MCP Server endpoints
|
|
23
|
-
* @param autoDetect - If true, auto-detect environment. If false (default), always use production
|
|
24
|
-
*/
|
|
25
|
-
export function getMcpEndpoints(autoDetect: boolean = false) {
|
|
26
|
-
const HOST = getHost(autoDetect);
|
|
27
|
-
return {
|
|
28
|
-
/** Base URL */
|
|
29
|
-
baseUrl: HOST,
|
|
30
|
-
/** Chat API endpoint */
|
|
31
|
-
chat: `${HOST}/api/chat`,
|
|
32
|
-
/** Search API endpoint */
|
|
33
|
-
search: `${HOST}/api/search`,
|
|
34
|
-
/** Conversations API endpoint */
|
|
35
|
-
conversations: `${HOST}/api/conversations`,
|
|
36
|
-
/** Health check endpoint */
|
|
37
|
-
health: `${HOST}/health`,
|
|
38
|
-
/** MCP protocol endpoint (Streamable HTTP) */
|
|
39
|
-
mcp: `${HOST}/mcp`,
|
|
40
|
-
/** SSE endpoint for legacy clients */
|
|
41
|
-
sse: `${HOST}/mcp/sse`,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* MCP Server endpoints (always production by default)
|
|
47
|
-
*/
|
|
48
|
-
export const mcpEndpoints = getMcpEndpoints(false);
|
|
49
|
-
|
|
50
|
-
// Export defaults for backwards compatibility
|
|
51
|
-
export const DEFAULT_CHAT_API_ENDPOINT = PROD_HOST + '/api/chat';
|
|
52
|
-
export const DEFAULT_MCP_BASE_URL = PROD_HOST;
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Chat sidebar layout configuration
|
|
56
|
-
*/
|
|
57
|
-
export const sidebarConfig = {
|
|
58
|
-
/** Minimum sidebar width in pixels */
|
|
59
|
-
minWidth: 320,
|
|
60
|
-
/** Maximum sidebar width in pixels */
|
|
61
|
-
maxWidth: 600,
|
|
62
|
-
/** Default sidebar width in pixels */
|
|
63
|
-
defaultWidth: 400,
|
|
64
|
-
/** Z-index for chat elements */
|
|
65
|
-
zIndex: 300,
|
|
66
|
-
/** Animation duration in milliseconds */
|
|
67
|
-
animationDuration: 200,
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Chat FAB (Floating Action Button) configuration
|
|
72
|
-
*/
|
|
73
|
-
export const fabConfig = {
|
|
74
|
-
/** Bottom offset in pixels */
|
|
75
|
-
bottom: 24,
|
|
76
|
-
/** Right offset in pixels */
|
|
77
|
-
right: 24,
|
|
78
|
-
/** Size of FAB button in pixels */
|
|
79
|
-
size: 56,
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* LocalStorage keys for chat state persistence
|
|
84
|
-
*/
|
|
85
|
-
export const storageKeys = {
|
|
86
|
-
/** Display mode (closed, floating, sidebar) */
|
|
87
|
-
mode: 'djangocfg-chat-mode',
|
|
88
|
-
/** User ID for conversation tracking */
|
|
89
|
-
userId: 'djangocfg-chat-user-id',
|
|
90
|
-
/** Chat messages history */
|
|
91
|
-
messages: 'djangocfg-chat-messages',
|
|
92
|
-
/** Sidebar width */
|
|
93
|
-
sidebarWidth: 'djangocfg-chat-sidebar-width',
|
|
94
|
-
};
|
|
@@ -1,327 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
createContext, ReactNode, useCallback, useContext, useEffect, useMemo, useRef, useState
|
|
5
|
-
} from 'react';
|
|
6
|
-
|
|
7
|
-
import { useIsMobile, useLocalStorage } from '@djangocfg/ui-core/hooks';
|
|
8
|
-
|
|
9
|
-
import { useAIChat } from '../hooks/useAIChat';
|
|
10
|
-
import { AIChatMessage, ChatDisplayMode, ChatWidgetConfig, mcpEndpoints} from '../types';
|
|
11
|
-
|
|
12
|
-
const STORAGE_KEY_MODE = 'djangocfg-ai-chat-mode';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* AI Chat context state
|
|
16
|
-
*/
|
|
17
|
-
export interface AIChatContextState {
|
|
18
|
-
/** All chat messages */
|
|
19
|
-
messages: AIChatMessage[];
|
|
20
|
-
/** Whether a request is in progress */
|
|
21
|
-
isLoading: boolean;
|
|
22
|
-
/** Last error if any */
|
|
23
|
-
error: Error | null;
|
|
24
|
-
/** Whether chat panel is open */
|
|
25
|
-
isOpen: boolean;
|
|
26
|
-
/** Whether chat is minimized */
|
|
27
|
-
isMinimized: boolean;
|
|
28
|
-
/** Configuration */
|
|
29
|
-
config: ChatWidgetConfig;
|
|
30
|
-
/** Current display mode */
|
|
31
|
-
displayMode: ChatDisplayMode;
|
|
32
|
-
/** Is on mobile device */
|
|
33
|
-
isMobile: boolean;
|
|
34
|
-
/** Thread ID for conversation */
|
|
35
|
-
threadId: string;
|
|
36
|
-
/** User ID for conversation */
|
|
37
|
-
userId: string;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* AI Chat context actions
|
|
42
|
-
*/
|
|
43
|
-
export interface AIChatContextActions {
|
|
44
|
-
/** Send a message */
|
|
45
|
-
sendMessage: (content: string) => Promise<void>;
|
|
46
|
-
/** Clear all messages */
|
|
47
|
-
clearMessages: () => void;
|
|
48
|
-
/** Open chat panel */
|
|
49
|
-
openChat: () => void;
|
|
50
|
-
/** Close chat panel */
|
|
51
|
-
closeChat: () => void;
|
|
52
|
-
/** Toggle chat panel */
|
|
53
|
-
toggleChat: () => void;
|
|
54
|
-
/** Minimize/restore chat */
|
|
55
|
-
toggleMinimize: () => void;
|
|
56
|
-
/** Set display mode */
|
|
57
|
-
setDisplayMode: (mode: ChatDisplayMode) => void;
|
|
58
|
-
/** Stop streaming response */
|
|
59
|
-
stopStreaming: () => void;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export type AIChatContextValue = AIChatContextState & AIChatContextActions;
|
|
63
|
-
|
|
64
|
-
const AIChatContext = createContext<AIChatContextValue | null>(null);
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* AI Chat provider props
|
|
68
|
-
*/
|
|
69
|
-
export interface AIChatProviderProps {
|
|
70
|
-
children: ReactNode;
|
|
71
|
-
/** API endpoint for AI chat (default: /api/ai/chat) */
|
|
72
|
-
apiEndpoint?: string;
|
|
73
|
-
/** Widget configuration */
|
|
74
|
-
config?: Partial<ChatWidgetConfig>;
|
|
75
|
-
/** Callback on error */
|
|
76
|
-
onError?: (error: Error) => void;
|
|
77
|
-
/** Enable streaming (default: true) */
|
|
78
|
-
enableStreaming?: boolean;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* AI Chat provider component
|
|
83
|
-
* Uses useAIChat hook with server-side persistence
|
|
84
|
-
*/
|
|
85
|
-
export function AIChatProvider({
|
|
86
|
-
children,
|
|
87
|
-
apiEndpoint = mcpEndpoints.chat,
|
|
88
|
-
config: userConfig = {},
|
|
89
|
-
onError,
|
|
90
|
-
enableStreaming = true,
|
|
91
|
-
}: AIChatProviderProps) {
|
|
92
|
-
// Use AI chat hook
|
|
93
|
-
const {
|
|
94
|
-
messages,
|
|
95
|
-
isLoading,
|
|
96
|
-
error,
|
|
97
|
-
threadId,
|
|
98
|
-
userId,
|
|
99
|
-
sendMessage: sendAIMessage,
|
|
100
|
-
clearMessages: clearAIMessages,
|
|
101
|
-
stopStreaming,
|
|
102
|
-
} = useAIChat({
|
|
103
|
-
apiEndpoint,
|
|
104
|
-
onError,
|
|
105
|
-
enableStreaming,
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
const [isMinimized, setIsMinimized] = useState(false);
|
|
109
|
-
|
|
110
|
-
// Display mode with localStorage persistence
|
|
111
|
-
const [storedMode, setStoredMode] = useLocalStorage<ChatDisplayMode>(STORAGE_KEY_MODE, 'closed');
|
|
112
|
-
|
|
113
|
-
const isMobile = useIsMobile();
|
|
114
|
-
|
|
115
|
-
// On mobile, sidebar mode is not available - fallback to floating
|
|
116
|
-
const displayMode: ChatDisplayMode = useMemo(() => {
|
|
117
|
-
if (isMobile && storedMode === 'sidebar') {
|
|
118
|
-
return 'floating';
|
|
119
|
-
}
|
|
120
|
-
return storedMode;
|
|
121
|
-
}, [isMobile, storedMode]);
|
|
122
|
-
|
|
123
|
-
// Derived state: isOpen is true when not in 'closed' mode
|
|
124
|
-
const isOpen = displayMode !== 'closed';
|
|
125
|
-
|
|
126
|
-
// Track isOpen in a ref for event handler
|
|
127
|
-
const isOpenRef = useRef(isOpen);
|
|
128
|
-
useEffect(() => {
|
|
129
|
-
isOpenRef.current = isOpen;
|
|
130
|
-
}, [isOpen]);
|
|
131
|
-
|
|
132
|
-
// Track last active mode (non-closed) to restore when reopening
|
|
133
|
-
const lastActiveModeRef = useRef<Exclude<ChatDisplayMode, 'closed'>>('floating');
|
|
134
|
-
useEffect(() => {
|
|
135
|
-
if (displayMode !== 'closed') {
|
|
136
|
-
lastActiveModeRef.current = displayMode;
|
|
137
|
-
}
|
|
138
|
-
}, [displayMode]);
|
|
139
|
-
|
|
140
|
-
const config: ChatWidgetConfig = useMemo(
|
|
141
|
-
() => ({
|
|
142
|
-
apiEndpoint,
|
|
143
|
-
title: 'DjangoCFG AI',
|
|
144
|
-
placeholder: 'Ask about DjangoCFG...',
|
|
145
|
-
greeting:
|
|
146
|
-
"Hi! I'm your DjangoCFG AI assistant powered by GPT. Ask me anything about configuration, features, or how to use the library.",
|
|
147
|
-
position: 'bottom-right',
|
|
148
|
-
variant: 'default',
|
|
149
|
-
...userConfig,
|
|
150
|
-
}),
|
|
151
|
-
[apiEndpoint, userConfig]
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
const sendMessage = useCallback(
|
|
155
|
-
async (content: string) => {
|
|
156
|
-
await sendAIMessage(content);
|
|
157
|
-
},
|
|
158
|
-
[sendAIMessage]
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
const clearMessages = useCallback(() => {
|
|
162
|
-
clearAIMessages();
|
|
163
|
-
}, [clearAIMessages]);
|
|
164
|
-
|
|
165
|
-
const openChat = useCallback(() => {
|
|
166
|
-
// Restore last active mode instead of always opening in floating
|
|
167
|
-
setStoredMode(lastActiveModeRef.current);
|
|
168
|
-
setIsMinimized(false);
|
|
169
|
-
}, [setStoredMode]);
|
|
170
|
-
|
|
171
|
-
const closeChat = useCallback(() => {
|
|
172
|
-
setStoredMode('closed');
|
|
173
|
-
setIsMinimized(false);
|
|
174
|
-
}, [setStoredMode]);
|
|
175
|
-
|
|
176
|
-
const toggleChat = useCallback(() => {
|
|
177
|
-
if (displayMode === 'closed') {
|
|
178
|
-
setStoredMode('floating');
|
|
179
|
-
setIsMinimized(false);
|
|
180
|
-
} else {
|
|
181
|
-
setStoredMode('closed');
|
|
182
|
-
}
|
|
183
|
-
}, [displayMode, setStoredMode]);
|
|
184
|
-
|
|
185
|
-
const toggleMinimize = useCallback(() => {
|
|
186
|
-
setIsMinimized((prev) => !prev);
|
|
187
|
-
}, []);
|
|
188
|
-
|
|
189
|
-
const setDisplayMode = useCallback(
|
|
190
|
-
(mode: ChatDisplayMode) => {
|
|
191
|
-
// On mobile, sidebar is not available
|
|
192
|
-
if (isMobile && mode === 'sidebar') {
|
|
193
|
-
setStoredMode('floating');
|
|
194
|
-
} else {
|
|
195
|
-
setStoredMode(mode);
|
|
196
|
-
}
|
|
197
|
-
setIsMinimized(false);
|
|
198
|
-
},
|
|
199
|
-
[isMobile, setStoredMode]
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
const value = useMemo<AIChatContextValue>(
|
|
203
|
-
() => ({
|
|
204
|
-
messages,
|
|
205
|
-
isLoading,
|
|
206
|
-
error,
|
|
207
|
-
isOpen,
|
|
208
|
-
isMinimized,
|
|
209
|
-
config,
|
|
210
|
-
displayMode,
|
|
211
|
-
isMobile,
|
|
212
|
-
threadId,
|
|
213
|
-
userId,
|
|
214
|
-
sendMessage,
|
|
215
|
-
clearMessages,
|
|
216
|
-
openChat,
|
|
217
|
-
closeChat,
|
|
218
|
-
toggleChat,
|
|
219
|
-
toggleMinimize,
|
|
220
|
-
setDisplayMode,
|
|
221
|
-
stopStreaming,
|
|
222
|
-
}),
|
|
223
|
-
[
|
|
224
|
-
messages,
|
|
225
|
-
isLoading,
|
|
226
|
-
error,
|
|
227
|
-
isOpen,
|
|
228
|
-
isMinimized,
|
|
229
|
-
config,
|
|
230
|
-
displayMode,
|
|
231
|
-
isMobile,
|
|
232
|
-
threadId,
|
|
233
|
-
userId,
|
|
234
|
-
sendMessage,
|
|
235
|
-
clearMessages,
|
|
236
|
-
openChat,
|
|
237
|
-
closeChat,
|
|
238
|
-
toggleChat,
|
|
239
|
-
toggleMinimize,
|
|
240
|
-
setDisplayMode,
|
|
241
|
-
stopStreaming,
|
|
242
|
-
]
|
|
243
|
-
);
|
|
244
|
-
|
|
245
|
-
// =============================================================================
|
|
246
|
-
// Global Chat Event Listener
|
|
247
|
-
// =============================================================================
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* Listen for mcp:chat:send events from useMcpChat hook
|
|
251
|
-
* This allows any component to trigger chat from anywhere in the app
|
|
252
|
-
*/
|
|
253
|
-
useEffect(() => {
|
|
254
|
-
// Register chat as available
|
|
255
|
-
if (typeof window !== 'undefined') {
|
|
256
|
-
(window as any).__MCP_CHAT_AVAILABLE__ = true;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
const handleChatEvent = (event: Event) => {
|
|
260
|
-
const customEvent = event as CustomEvent<import('../types').McpChatEventDetail>;
|
|
261
|
-
const { message, context, autoSend = true, displayMode: requestedMode } = customEvent.detail;
|
|
262
|
-
|
|
263
|
-
// Send confirmation that event was handled
|
|
264
|
-
window.dispatchEvent(new CustomEvent('mcp:chat:handled'));
|
|
265
|
-
|
|
266
|
-
// Format message with context if provided
|
|
267
|
-
let fullMessage = message;
|
|
268
|
-
if (context) {
|
|
269
|
-
if (context.type) {
|
|
270
|
-
fullMessage = `[${context.type.toUpperCase()}] ${message}`;
|
|
271
|
-
}
|
|
272
|
-
if (context.data) {
|
|
273
|
-
fullMessage += `\n\n**Context:**\n\`\`\`json\n${JSON.stringify(context.data, null, 2)}\n\`\`\``;
|
|
274
|
-
}
|
|
275
|
-
if (context.source) {
|
|
276
|
-
fullMessage += `\n\n_Source: ${context.source}_`;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// Open chat in requested mode, or keep current mode if already open
|
|
281
|
-
if (requestedMode) {
|
|
282
|
-
setDisplayMode(requestedMode);
|
|
283
|
-
} else if (!isOpenRef.current) {
|
|
284
|
-
// Only open if chat is currently closed
|
|
285
|
-
openChat();
|
|
286
|
-
}
|
|
287
|
-
// If already open, keep current mode
|
|
288
|
-
|
|
289
|
-
// Auto-send message if requested
|
|
290
|
-
if (autoSend) {
|
|
291
|
-
// Small delay to ensure chat is open and ready
|
|
292
|
-
setTimeout(() => {
|
|
293
|
-
sendMessage(fullMessage);
|
|
294
|
-
}, 100);
|
|
295
|
-
}
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
window.addEventListener('mcp:chat:send', handleChatEvent);
|
|
299
|
-
|
|
300
|
-
return () => {
|
|
301
|
-
window.removeEventListener('mcp:chat:send', handleChatEvent);
|
|
302
|
-
if (typeof window !== 'undefined') {
|
|
303
|
-
(window as any).__MCP_CHAT_AVAILABLE__ = false;
|
|
304
|
-
}
|
|
305
|
-
};
|
|
306
|
-
}, [sendMessage, setDisplayMode, openChat]);
|
|
307
|
-
|
|
308
|
-
return <AIChatContext.Provider value={value}>{children}</AIChatContext.Provider>;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Hook to access AI chat context
|
|
313
|
-
*/
|
|
314
|
-
export function useAIChatContext(): AIChatContextValue {
|
|
315
|
-
const context = useContext(AIChatContext);
|
|
316
|
-
if (!context) {
|
|
317
|
-
throw new Error('useAIChatContext must be used within an AIChatProvider');
|
|
318
|
-
}
|
|
319
|
-
return context;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* Hook to check if AI chat context is available
|
|
324
|
-
*/
|
|
325
|
-
export function useAIChatContextOptional(): AIChatContextValue | null {
|
|
326
|
-
return useContext(AIChatContext);
|
|
327
|
-
}
|