@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.
Files changed (97) hide show
  1. package/README.md +3 -17
  2. package/package.json +18 -18
  3. package/src/components/errors/ErrorLayout.tsx +2 -2
  4. package/src/components/errors/ErrorsTracker/index.ts +1 -0
  5. package/src/components/errors/ErrorsTracker/utils/formatters.ts +23 -1
  6. package/src/hooks/useLogout.ts +9 -12
  7. package/src/layouts/AppLayout/AppLayout.tsx +20 -8
  8. package/src/layouts/AppLayout/BaseApp.tsx +5 -28
  9. package/src/layouts/AuthLayout/AuthLayout.tsx +51 -22
  10. package/src/layouts/AuthLayout/README.md +78 -0
  11. package/src/layouts/AuthLayout/components/shared/AuthDivider.tsx +2 -2
  12. package/src/layouts/AuthLayout/components/shared/AuthError.tsx +10 -2
  13. package/src/layouts/AuthLayout/components/shared/AuthFooter.tsx +2 -2
  14. package/src/layouts/AuthLayout/components/shared/AuthHeader.tsx +3 -2
  15. package/src/layouts/AuthLayout/components/shared/AuthOTPInput.tsx +4 -1
  16. package/src/layouts/AuthLayout/components/shared/TermsCheckbox.tsx +2 -2
  17. package/src/layouts/AuthLayout/components/shared/index.ts +0 -2
  18. package/src/layouts/AuthLayout/components/steps/IdentifierStep.tsx +25 -80
  19. package/src/layouts/AuthLayout/components/steps/OTPStep.tsx +8 -13
  20. package/src/layouts/AuthLayout/components/steps/SetupStep/SetupComplete.tsx +2 -2
  21. package/src/layouts/AuthLayout/components/steps/SetupStep/SetupLoading.tsx +2 -2
  22. package/src/layouts/AuthLayout/components/steps/SetupStep/SetupQRCode.tsx +2 -2
  23. package/src/layouts/AuthLayout/components/steps/TwoFactorStep.tsx +61 -42
  24. package/src/layouts/AuthLayout/context.tsx +0 -2
  25. package/src/layouts/AuthLayout/index.ts +9 -6
  26. package/src/layouts/AuthLayout/styles/auth.css +265 -120
  27. package/src/layouts/AuthLayout/types.ts +60 -7
  28. package/src/layouts/ProfileLayout/.claude/.sidecar/activity.jsonl +2 -0
  29. package/src/layouts/ProfileLayout/.claude/.sidecar/history/2026-03-15.md +35 -0
  30. package/src/layouts/ProfileLayout/.claude/.sidecar/review.md +35 -0
  31. package/src/layouts/ProfileLayout/.claude/.sidecar/scan.log +3 -0
  32. package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-001.md +18 -0
  33. package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-002.md +19 -0
  34. package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-003.md +18 -0
  35. package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-004.md +18 -0
  36. package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-005.md +18 -0
  37. package/src/layouts/ProfileLayout/.claude/.sidecar/usage.json +5 -0
  38. package/src/layouts/ProfileLayout/ProfileLayout.tsx +52 -403
  39. package/src/layouts/ProfileLayout/components/ActionButton.tsx +38 -0
  40. package/src/layouts/ProfileLayout/components/DeleteAccountSection.tsx +109 -148
  41. package/src/layouts/ProfileLayout/components/EditableField.tsx +119 -0
  42. package/src/layouts/ProfileLayout/components/Section.tsx +22 -0
  43. package/src/layouts/ProfileLayout/components/index.ts +4 -1
  44. package/src/layouts/ProfileLayout/context.tsx +31 -0
  45. package/src/layouts/PublicLayout/components/PublicMobileDrawer.tsx +2 -2
  46. package/src/layouts/PublicLayout/components/PublicNavigation.tsx +2 -2
  47. package/src/layouts/_components/UserMenu.tsx +2 -2
  48. package/src/layouts/types/README.md +0 -20
  49. package/src/layouts/types/index.ts +2 -2
  50. package/src/layouts/types/layout.types.ts +2 -5
  51. package/src/layouts/types/providers.types.ts +0 -27
  52. package/src/snippets/AuthDialog/AuthDialog.tsx +2 -2
  53. package/src/snippets/Breadcrumbs.tsx +2 -2
  54. package/src/snippets/index.ts +0 -67
  55. package/src/layouts/AuthLayout/components/shared/ChannelToggle.tsx +0 -56
  56. package/src/snippets/McpChat/README.md +0 -441
  57. package/src/snippets/McpChat/components/AIChatWidget.tsx +0 -361
  58. package/src/snippets/McpChat/components/AskAIButton.tsx +0 -92
  59. package/src/snippets/McpChat/components/ChatMessages.tsx +0 -138
  60. package/src/snippets/McpChat/components/ChatPanel.tsx +0 -131
  61. package/src/snippets/McpChat/components/ChatSidebar.tsx +0 -156
  62. package/src/snippets/McpChat/components/ChatWidget.tsx +0 -115
  63. package/src/snippets/McpChat/components/MessageBubble.tsx +0 -142
  64. package/src/snippets/McpChat/components/MessageInput.tsx +0 -140
  65. package/src/snippets/McpChat/components/index.ts +0 -24
  66. package/src/snippets/McpChat/config.ts +0 -94
  67. package/src/snippets/McpChat/context/AIChatContext.tsx +0 -327
  68. package/src/snippets/McpChat/context/ChatContext.tsx +0 -361
  69. package/src/snippets/McpChat/context/index.ts +0 -7
  70. package/src/snippets/McpChat/hooks/index.ts +0 -6
  71. package/src/snippets/McpChat/hooks/useAIChat.ts +0 -503
  72. package/src/snippets/McpChat/hooks/useChatLayout.ts +0 -442
  73. package/src/snippets/McpChat/hooks/useMcpChat.ts +0 -90
  74. package/src/snippets/McpChat/index.ts +0 -79
  75. package/src/snippets/McpChat/types.ts +0 -189
  76. package/src/snippets/PWAInstall/@docs/README.md +0 -92
  77. package/src/snippets/PWAInstall/@docs/research/ios-android-install-flows.md +0 -576
  78. package/src/snippets/PWAInstall/README.md +0 -235
  79. package/src/snippets/PWAInstall/components/A2HSHint.tsx +0 -236
  80. package/src/snippets/PWAInstall/components/DesktopGuide.tsx +0 -234
  81. package/src/snippets/PWAInstall/components/IOSGuide.tsx +0 -29
  82. package/src/snippets/PWAInstall/components/IOSGuideDrawer.tsx +0 -103
  83. package/src/snippets/PWAInstall/components/IOSGuideModal.tsx +0 -103
  84. package/src/snippets/PWAInstall/components/PWAPageResumeManager.tsx +0 -33
  85. package/src/snippets/PWAInstall/context/InstallContext.tsx +0 -102
  86. package/src/snippets/PWAInstall/hooks/useInstallPrompt.ts +0 -168
  87. package/src/snippets/PWAInstall/hooks/useIsPWA.ts +0 -116
  88. package/src/snippets/PWAInstall/hooks/usePWAPageResume.ts +0 -163
  89. package/src/snippets/PWAInstall/index.ts +0 -80
  90. package/src/snippets/PWAInstall/types/components.ts +0 -95
  91. package/src/snippets/PWAInstall/types/config.ts +0 -29
  92. package/src/snippets/PWAInstall/types/index.ts +0 -26
  93. package/src/snippets/PWAInstall/types/install.ts +0 -38
  94. package/src/snippets/PWAInstall/types/platform.ts +0 -29
  95. package/src/snippets/PWAInstall/utils/localStorage.ts +0 -181
  96. package/src/snippets/PWAInstall/utils/logger.ts +0 -149
  97. package/src/snippets/PWAInstall/utils/platform.ts +0 -151
@@ -1,361 +0,0 @@
1
- 'use client';
2
-
3
- import React, {
4
- createContext, ReactNode, useCallback, useContext, useEffect, useMemo, useRef, useState
5
- } from 'react';
6
- import { v4 as uuidv4 } from 'uuid';
7
-
8
- import { useIsMobile, useLocalStorage } from '@djangocfg/ui-core/hooks';
9
-
10
- import { storageKeys } from '../config';
11
-
12
- import type { AIChatMessage, ChatApiResponse, AIChatSource, ChatWidgetConfig, ChatDisplayMode } from '../types';
13
- const MAX_STORED_MESSAGES = 50;
14
-
15
- function generateMessageId(): string {
16
- return `msg_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
17
- }
18
-
19
- /**
20
- * Serialized message format for localStorage
21
- */
22
- interface SerializedMessage {
23
- id: string;
24
- role: 'user' | 'assistant' | 'system';
25
- content: string;
26
- timestamp: string; // ISO string
27
- sources?: AIChatSource[];
28
- }
29
-
30
- /**
31
- * Chat context state
32
- */
33
- export interface ChatContextState {
34
- /** All chat messages */
35
- messages: AIChatMessage[];
36
- /** Whether a request is in progress */
37
- isLoading: boolean;
38
- /** Last error if any */
39
- error: Error | null;
40
- /** Whether chat panel is open */
41
- isOpen: boolean;
42
- /** Whether chat is minimized */
43
- isMinimized: boolean;
44
- /** Configuration */
45
- config: ChatWidgetConfig;
46
- /** Current display mode */
47
- displayMode: ChatDisplayMode;
48
- /** Is on mobile device */
49
- isMobile: boolean;
50
- /** User ID for this session */
51
- userId: string;
52
- }
53
-
54
- /**
55
- * Chat context actions
56
- */
57
- export interface ChatContextActions {
58
- /** Send a message */
59
- sendMessage: (content: string) => Promise<void>;
60
- /** Clear all messages */
61
- clearMessages: () => void;
62
- /** Open chat panel */
63
- openChat: () => void;
64
- /** Close chat panel */
65
- closeChat: () => void;
66
- /** Toggle chat panel */
67
- toggleChat: () => void;
68
- /** Minimize/restore chat */
69
- toggleMinimize: () => void;
70
- /** Set display mode */
71
- setDisplayMode: (mode: ChatDisplayMode) => void;
72
- }
73
-
74
- export type ChatContextValue = ChatContextState & ChatContextActions;
75
-
76
- const ChatContext = createContext<ChatContextValue | null>(null);
77
-
78
- /**
79
- * Chat provider props
80
- */
81
- export interface ChatProviderProps {
82
- children: ReactNode;
83
- /** API endpoint for chat */
84
- apiEndpoint?: string;
85
- /** Widget configuration */
86
- config?: Partial<ChatWidgetConfig>;
87
- /** Callback on error */
88
- onError?: (error: Error) => void;
89
- }
90
-
91
- /**
92
- * Chat provider component
93
- */
94
- export function ChatProvider({
95
- children,
96
- apiEndpoint = '/api/chat',
97
- config: userConfig = {},
98
- onError,
99
- }: ChatProviderProps) {
100
- const [messages, setMessages] = useState<AIChatMessage[]>([]);
101
- const [isLoading, setIsLoading] = useState(false);
102
- const [error, setError] = useState<Error | null>(null);
103
- const [isMinimized, setIsMinimized] = useState(false);
104
- const isHydratedRef = useRef(false);
105
- const mobileResetRef = useRef(false);
106
-
107
- // Display mode with localStorage persistence
108
- const [storedMode, setStoredMode] = useLocalStorage<ChatDisplayMode>(storageKeys.mode, 'closed');
109
-
110
- // User ID with localStorage persistence
111
- const [userId, setUserId] = useLocalStorage<string>(storageKeys.userId, '');
112
-
113
- // Messages storage (serialized)
114
- const [storedMessages, setStoredMessages] = useLocalStorage<SerializedMessage[]>(storageKeys.messages, []);
115
-
116
- const isMobile = useIsMobile();
117
-
118
- // On mobile, always start closed on page load (don't restore state)
119
- useEffect(() => {
120
- if (isMobile && !mobileResetRef.current && storedMode !== 'closed') {
121
- mobileResetRef.current = true;
122
- setStoredMode('closed');
123
- }
124
- }, [isMobile, storedMode, setStoredMode]);
125
-
126
- // Generate user ID if not exists
127
- useEffect(() => {
128
- if (!userId) {
129
- setUserId(uuidv4());
130
- }
131
- }, [userId, setUserId]);
132
-
133
- // Load messages from localStorage on mount (once)
134
- useEffect(() => {
135
- if (isHydratedRef.current) return;
136
- isHydratedRef.current = true;
137
-
138
- if (storedMessages.length > 0) {
139
- const hydratedMessages: AIChatMessage[] = storedMessages.map((msg) => ({
140
- ...msg,
141
- timestamp: new Date(msg.timestamp),
142
- }));
143
- setMessages(hydratedMessages);
144
- }
145
- // eslint-disable-next-line react-hooks/exhaustive-deps
146
- }, [storedMessages]); // Depend on storedMessages to wait for localStorage
147
-
148
- // Save messages to localStorage when they change
149
- useEffect(() => {
150
- if (!isHydratedRef.current) return;
151
-
152
- const toStore: SerializedMessage[] = messages.slice(-MAX_STORED_MESSAGES).map((msg) => ({
153
- id: msg.id,
154
- role: msg.role,
155
- content: msg.content,
156
- timestamp: msg.timestamp.toISOString(),
157
- sources: msg.sources,
158
- }));
159
- setStoredMessages(toStore);
160
- // eslint-disable-next-line react-hooks/exhaustive-deps
161
- }, [messages]);
162
-
163
- // On mobile, sidebar mode is not available - fallback to floating
164
- const displayMode: ChatDisplayMode = useMemo(() => {
165
- if (isMobile && storedMode === 'sidebar') {
166
- return 'floating';
167
- }
168
- return storedMode;
169
- }, [isMobile, storedMode]);
170
-
171
- // Derived state: isOpen is true when not in 'closed' mode
172
- const isOpen = displayMode !== 'closed';
173
-
174
- const config: ChatWidgetConfig = useMemo(
175
- () => ({
176
- apiEndpoint,
177
- title: 'DjangoCFG AI',
178
- placeholder: 'Ask about DjangoCFG...',
179
- greeting:
180
- "Hi! I'm your DjangoCFG documentation assistant. Ask me anything about configuration, features, or how to use the library.",
181
- position: 'bottom-right',
182
- variant: 'default',
183
- ...userConfig,
184
- }),
185
- [apiEndpoint, userConfig]
186
- );
187
-
188
- const sendMessage = useCallback(
189
- async (content: string) => {
190
- if (!content.trim() || isLoading) return;
191
-
192
- const userMessage: AIChatMessage = {
193
- id: generateMessageId(),
194
- role: 'user',
195
- content: content.trim(),
196
- timestamp: new Date(),
197
- };
198
-
199
- setMessages((prev) => [...prev, userMessage]);
200
- setIsLoading(true);
201
- setError(null);
202
-
203
- try {
204
- const response = await fetch(config.apiEndpoint || apiEndpoint, {
205
- method: 'POST',
206
- headers: { 'Content-Type': 'application/json' },
207
- body: JSON.stringify({
208
- query: content,
209
- userId: userId || undefined,
210
- }),
211
- });
212
-
213
- if (!response.ok) {
214
- throw new Error(`HTTP error: ${response.status}`);
215
- }
216
-
217
- const data: ChatApiResponse = await response.json();
218
-
219
- if (!data.success) {
220
- throw new Error(data.error || 'Failed to get response');
221
- }
222
-
223
- const sources: AIChatSource[] =
224
- data.results?.map((r) => ({
225
- title: r.chunk.title,
226
- path: r.chunk.path,
227
- url: r.chunk.url,
228
- section: r.chunk.section,
229
- score: r.score,
230
- })) || [];
231
-
232
- const assistantMessage: AIChatMessage = {
233
- id: generateMessageId(),
234
- role: 'assistant',
235
- content: data.answer || 'I found some relevant documentation.',
236
- timestamp: new Date(),
237
- sources,
238
- };
239
-
240
- setMessages((prev) => [...prev, assistantMessage]);
241
- } catch (err) {
242
- const error = err instanceof Error ? err : new Error('Unknown error');
243
- setError(error);
244
- onError?.(error);
245
-
246
- const errorMessage: AIChatMessage = {
247
- id: generateMessageId(),
248
- role: 'assistant',
249
- content: `Sorry, I encountered an error: ${error.message}. Please try again.`,
250
- timestamp: new Date(),
251
- };
252
-
253
- setMessages((prev) => [...prev, errorMessage]);
254
- } finally {
255
- setIsLoading(false);
256
- }
257
- },
258
- [apiEndpoint, config.apiEndpoint, isLoading, onError, userId]
259
- );
260
-
261
- const clearMessages = useCallback(() => {
262
- setMessages([]);
263
- setStoredMessages([]);
264
- setError(null);
265
- }, [setStoredMessages]);
266
-
267
- const openChat = useCallback(() => {
268
- setStoredMode('floating');
269
- setIsMinimized(false);
270
- }, [setStoredMode]);
271
-
272
- const closeChat = useCallback(() => {
273
- setStoredMode('closed');
274
- setIsMinimized(false);
275
- }, [setStoredMode]);
276
-
277
- const toggleChat = useCallback(() => {
278
- if (displayMode === 'closed') {
279
- setStoredMode('floating');
280
- setIsMinimized(false);
281
- } else {
282
- setStoredMode('closed');
283
- }
284
- }, [displayMode, setStoredMode]);
285
-
286
- const toggleMinimize = useCallback(() => {
287
- setIsMinimized((prev) => !prev);
288
- }, []);
289
-
290
- const setDisplayMode = useCallback(
291
- (mode: ChatDisplayMode) => {
292
- // On mobile, sidebar is not available
293
- if (isMobile && mode === 'sidebar') {
294
- setStoredMode('floating');
295
- } else {
296
- setStoredMode(mode);
297
- }
298
- setIsMinimized(false);
299
- },
300
- [isMobile, setStoredMode]
301
- );
302
-
303
- const value = useMemo<ChatContextValue>(
304
- () => ({
305
- messages,
306
- isLoading,
307
- error,
308
- isOpen,
309
- isMinimized,
310
- config,
311
- displayMode,
312
- isMobile,
313
- userId: userId || '',
314
- sendMessage,
315
- clearMessages,
316
- openChat,
317
- closeChat,
318
- toggleChat,
319
- toggleMinimize,
320
- setDisplayMode,
321
- }),
322
- [
323
- messages,
324
- isLoading,
325
- error,
326
- isOpen,
327
- isMinimized,
328
- config,
329
- displayMode,
330
- isMobile,
331
- userId,
332
- sendMessage,
333
- clearMessages,
334
- openChat,
335
- closeChat,
336
- toggleChat,
337
- toggleMinimize,
338
- setDisplayMode,
339
- ]
340
- );
341
-
342
- return <ChatContext.Provider value={value}>{children}</ChatContext.Provider>;
343
- }
344
-
345
- /**
346
- * Hook to access chat context
347
- */
348
- export function useChatContext(): ChatContextValue {
349
- const context = useContext(ChatContext);
350
- if (!context) {
351
- throw new Error('useChatContext must be used within a ChatProvider');
352
- }
353
- return context;
354
- }
355
-
356
- /**
357
- * Hook to check if chat context is available
358
- */
359
- export function useChatContextOptional(): ChatContextValue | null {
360
- return useContext(ChatContext);
361
- }
@@ -1,7 +0,0 @@
1
- 'use client';
2
-
3
- export { ChatProvider, useChatContext, useChatContextOptional } from './ChatContext';
4
- export type { ChatContextState, ChatContextActions, ChatContextValue, ChatProviderProps } from './ChatContext';
5
-
6
- export { AIChatProvider, useAIChatContext, useAIChatContextOptional } from './AIChatContext';
7
- export type { AIChatContextState, AIChatContextActions, AIChatContextValue, AIChatProviderProps } from './AIChatContext';
@@ -1,6 +0,0 @@
1
- 'use client';
2
-
3
- export { useAIChat } from './useAIChat';
4
- export { useChatLayout } from './useChatLayout';
5
- export { useMcpChat } from './useMcpChat';
6
- export type { ChatLayoutConfig, UseChatLayoutReturn } from './useChatLayout';