@messenger-box/tailwind-ui-inbox 10.0.3-alpha.71 → 10.0.3-alpha.73

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 (143) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/components/AIAgent/AIAgent.d.ts +14 -0
  3. package/lib/components/AIAgent/AIAgent.d.ts.map +1 -0
  4. package/lib/components/AIAgent/AIAgent.js +1148 -0
  5. package/lib/components/AIAgent/AIAgent.js.map +1 -0
  6. package/lib/components/AIAgent/index.d.ts +2 -0
  7. package/lib/components/AIAgent/index.d.ts.map +1 -0
  8. package/lib/components/InboxMessage/InputComponent.d.ts +9 -0
  9. package/lib/components/InboxMessage/InputComponent.d.ts.map +1 -0
  10. package/lib/components/InboxMessage/InputComponent.js +210 -0
  11. package/lib/components/InboxMessage/InputComponent.js.map +1 -0
  12. package/lib/components/InboxMessage/MessageInput.d.ts.map +1 -1
  13. package/lib/components/InboxMessage/MessageInput.js +14 -10
  14. package/lib/components/InboxMessage/MessageInput.js.map +1 -1
  15. package/lib/components/InboxMessage/MessageInputComponent.d.ts +9 -0
  16. package/lib/components/InboxMessage/MessageInputComponent.d.ts.map +1 -0
  17. package/lib/components/InboxMessage/Messages.d.ts.map +1 -1
  18. package/lib/components/InboxMessage/Messages.js +4 -54
  19. package/lib/components/InboxMessage/Messages.js.map +1 -1
  20. package/lib/components/InboxMessage/MessagesBuilderUi.d.ts +17 -0
  21. package/lib/components/InboxMessage/MessagesBuilderUi.d.ts.map +1 -0
  22. package/lib/components/InboxMessage/UploadImageButton.d.ts +1 -0
  23. package/lib/components/InboxMessage/UploadImageButton.d.ts.map +1 -1
  24. package/lib/components/InboxMessage/UploadImageButton.js +3 -3
  25. package/lib/components/InboxMessage/UploadImageButton.js.map +1 -1
  26. package/lib/components/InboxMessage/index.d.ts +3 -0
  27. package/lib/components/InboxMessage/index.d.ts.map +1 -1
  28. package/lib/components/InboxMessage/message-widgets/CommonMessage.d.ts.map +1 -1
  29. package/lib/components/InboxMessage/message-widgets/CommonMessage.js +11 -6
  30. package/lib/components/InboxMessage/message-widgets/CommonMessage.js.map +1 -1
  31. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts +14 -0
  32. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts.map +1 -0
  33. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js +1525 -0
  34. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js.map +1 -0
  35. package/lib/components/InboxMessage/message-widgets/PlainMessage.d.ts.map +1 -1
  36. package/lib/components/InboxMessage/message-widgets/PlainMessage.js +6 -3
  37. package/lib/components/InboxMessage/message-widgets/PlainMessage.js.map +1 -1
  38. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.d.ts.map +1 -1
  39. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.js +207 -12
  40. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.js.map +1 -1
  41. package/lib/components/InboxMessage/message-widgets/index.d.ts +1 -0
  42. package/lib/components/InboxMessage/message-widgets/index.d.ts.map +1 -1
  43. package/lib/components/index.d.ts +2 -1
  44. package/lib/components/index.d.ts.map +1 -1
  45. package/lib/compute.d.ts.map +1 -1
  46. package/lib/compute.js +79 -3
  47. package/lib/compute.js.map +1 -1
  48. package/lib/config/env-config.d.ts +6 -0
  49. package/lib/config/env-config.d.ts.map +1 -1
  50. package/lib/config/env-config.js +19 -1
  51. package/lib/config/env-config.js.map +1 -1
  52. package/lib/container/AiInbox.d.ts +15 -0
  53. package/lib/container/AiInbox.d.ts.map +1 -0
  54. package/lib/container/AiInboxWithLoader.d.ts +36 -0
  55. package/lib/container/AiInboxWithLoader.d.ts.map +1 -0
  56. package/lib/container/AiLandingInput.d.ts +4 -0
  57. package/lib/container/AiLandingInput.d.ts.map +1 -0
  58. package/lib/container/AiLandingInput.js +164 -0
  59. package/lib/container/AiLandingInput.js.map +1 -0
  60. package/lib/container/Inbox.d.ts.map +1 -1
  61. package/lib/container/Inbox.js +6 -4
  62. package/lib/container/Inbox.js.map +1 -1
  63. package/lib/container/InboxAiMessagesLoader.d.ts +36 -0
  64. package/lib/container/InboxAiMessagesLoader.d.ts.map +1 -0
  65. package/lib/container/InboxAiMessagesLoader.js +44 -0
  66. package/lib/container/InboxAiMessagesLoader.js.map +1 -0
  67. package/lib/container/InboxContainer.d.ts +12 -0
  68. package/lib/container/InboxContainer.d.ts.map +1 -0
  69. package/lib/container/InboxContainer.js +31 -0
  70. package/lib/container/InboxContainer.js.map +1 -0
  71. package/lib/container/InboxTemplate1.d.ts +15 -0
  72. package/lib/container/InboxTemplate1.d.ts.map +1 -0
  73. package/lib/container/InboxTemplate1WithLoader.d.ts +36 -0
  74. package/lib/container/InboxTemplate1WithLoader.d.ts.map +1 -0
  75. package/lib/container/InboxTemplate2.d.ts +15 -0
  76. package/lib/container/InboxTemplate2.d.ts.map +1 -0
  77. package/lib/container/InboxWithAiLoader.d.ts +15 -0
  78. package/lib/container/InboxWithAiLoader.d.ts.map +1 -0
  79. package/lib/container/InboxWithAiLoader.js +56 -0
  80. package/lib/container/InboxWithAiLoader.js.map +1 -0
  81. package/lib/container/ServiceInbox.js +1 -1
  82. package/lib/container/ServiceInbox.js.map +1 -1
  83. package/lib/container/ThreadMessages.js +1 -1
  84. package/lib/container/ThreadMessages.js.map +1 -1
  85. package/lib/container/ThreadMessagesInbox.js +1 -1
  86. package/lib/container/ThreadMessagesInbox.js.map +1 -1
  87. package/lib/container/Threads.js +1 -1
  88. package/lib/container/Threads.js.map +1 -1
  89. package/lib/container/index.d.ts +4 -1
  90. package/lib/container/index.d.ts.map +1 -1
  91. package/lib/index.d.ts +3 -2
  92. package/lib/index.d.ts.map +1 -1
  93. package/lib/index.js +1 -1
  94. package/lib/machines/aiAgentMachine.d.ts +3 -0
  95. package/lib/machines/aiAgentMachine.d.ts.map +1 -0
  96. package/lib/machines/aiAgentMachine.js +1040 -0
  97. package/lib/machines/aiAgentMachine.js.map +1 -0
  98. package/lib/machines/types.d.ts +77 -0
  99. package/lib/machines/types.d.ts.map +1 -0
  100. package/lib/routes.json +40 -0
  101. package/lib/templates/InboxWithAi.d.ts +15 -0
  102. package/lib/templates/InboxWithAi.d.ts.map +1 -0
  103. package/lib/templates/InboxWithAi.js +405 -0
  104. package/lib/templates/InboxWithAi.js.map +1 -0
  105. package/lib/templates/InboxWithAi.tsx +502 -0
  106. package/lib/templates/index.d.ts +2 -0
  107. package/lib/templates/index.d.ts.map +1 -0
  108. package/lib/templates/index.ts +1 -0
  109. package/package.json +7 -5
  110. package/src/components/AIAgent/AIAgent.tsx +1351 -0
  111. package/src/components/AIAgent/README.md +82 -0
  112. package/src/components/AIAgent/index.ts +1 -0
  113. package/src/components/InboxMessage/InputComponent.tsx +263 -0
  114. package/src/components/InboxMessage/MessageInput.tsx +73 -66
  115. package/src/components/InboxMessage/MessageInputComponent.tsx +245 -0
  116. package/src/components/InboxMessage/Messages.tsx +2 -56
  117. package/src/components/InboxMessage/MessagesBuilderUi.tsx +205 -0
  118. package/src/components/InboxMessage/UploadImageButton.tsx +3 -2
  119. package/src/components/InboxMessage/index.ts +3 -0
  120. package/src/components/InboxMessage/message-widgets/CommonMessage.tsx +39 -21
  121. package/src/components/InboxMessage/message-widgets/ModernMessageGroup.tsx +1968 -0
  122. package/src/components/InboxMessage/message-widgets/PlainMessage.tsx +6 -2
  123. package/src/components/InboxMessage/message-widgets/SlackLikeMessageGroup.tsx +306 -54
  124. package/src/components/InboxMessage/message-widgets/index.ts +1 -0
  125. package/src/components/index.ts +4 -0
  126. package/src/compute.ts +83 -2
  127. package/src/config/env-config.ts +6 -0
  128. package/src/container/AiInbox.tsx +1796 -0
  129. package/src/container/AiInboxWithLoader.tsx +356 -0
  130. package/src/container/AiLandingInput.tsx +168 -0
  131. package/src/container/Inbox.tsx +8 -5
  132. package/src/container/InboxAiMessagesLoader.tsx +58 -0
  133. package/src/container/InboxContainer.tsx +35 -0
  134. package/src/container/InboxTemplate1.tsx +1542 -0
  135. package/src/container/InboxTemplate1WithLoader.tsx +338 -0
  136. package/src/container/InboxTemplate2.tsx +1606 -0
  137. package/src/container/InboxWithAiLoader.tsx +76 -0
  138. package/src/container/index.ts +21 -1
  139. package/src/index.ts +12 -1
  140. package/src/machines/aiAgentMachine.ts +1248 -0
  141. package/src/machines/types.ts +59 -0
  142. package/src/templates/InboxWithAi.tsx +502 -0
  143. package/src/templates/index.ts +1 -0
@@ -0,0 +1,356 @@
1
+ import React, { useMemo, useCallback } from 'react';
2
+ import { useParams, useLocation } from '@remix-run/react';
3
+ import {
4
+ useGetChannelsByUserQuery,
5
+ useGetChannelsByUserWithLastMessageQuery,
6
+ useMessagesQuery,
7
+ useViewChannelDetailQuery,
8
+ } from 'common/graphql';
9
+ import { RoomType } from 'common';
10
+ import { config } from '../config';
11
+ // import Inbox from './Inbox';
12
+ import Inbox from './AiInbox';
13
+ import AiInbox from './AiInbox';
14
+ import InboxTemplate1 from './InboxTemplate1';
15
+ import InboxTemplate2 from './InboxTemplate2';
16
+ const { MESSAGES_PER_PAGE } = config;
17
+
18
+ // Enhanced query parameters generator with better typing and flexibility
19
+ export const queryParamsGenerator = (params: {
20
+ role?: string;
21
+ criteria?: Record<string, any>;
22
+ supportServices?: boolean;
23
+ orgName?: string;
24
+ }) => ({
25
+ variable1: {
26
+ role: params.role,
27
+ criteria: {
28
+ ...params.criteria,
29
+ ...(params.orgName && { orgName: params.orgName }),
30
+ },
31
+ supportServices: params.supportServices ? true : false,
32
+ supportServiceCriteria: params.supportServices
33
+ ? {
34
+ type: RoomType.Service,
35
+ }
36
+ : undefined,
37
+ orderBy: {
38
+ lastPostAt: 'desc',
39
+ },
40
+ },
41
+ });
42
+
43
+ // Enhanced Skeleton Components
44
+ const InboxSkeleton = React.memo(({ showRightSidebar = false }: { showRightSidebar?: boolean }) => (
45
+ <div
46
+ className="h-full border-t border-gray-300 flex overflow-hidden animate-pulse"
47
+ style={{ height: '100vh !important' }}
48
+ >
49
+ {/* Left Sidebar Skeleton */}
50
+ <div className="flex-shrink-0 w-full md:w-80 lg:w-96 xl:w-[420px] bg-gray-50 border-r border-gray-300 overflow-hidden">
51
+ {/* Header skeleton */}
52
+ <div className="p-4 border-b border-gray-200">
53
+ <div className="flex items-center justify-between mb-4">
54
+ <div className="h-6 bg-gray-300 rounded w-24"></div>
55
+ <div className="h-8 w-8 bg-gray-300 rounded-full"></div>
56
+ </div>
57
+ {/* Search bar skeleton */}
58
+ <div className="h-10 bg-gray-300 rounded-lg w-full"></div>
59
+ </div>
60
+
61
+ {/* Conversation list skeleton */}
62
+ <div className="p-4 space-y-3">
63
+ {Array.from({ length: 8 }).map((_, index) => (
64
+ <div key={index} className="flex items-center space-x-3 p-3 rounded-lg">
65
+ {/* Avatar skeleton */}
66
+ <div className="h-12 w-12 bg-gray-300 rounded-full flex-shrink-0"></div>
67
+ <div className="flex-1 min-w-0">
68
+ {/* Name skeleton */}
69
+ <div className="h-4 bg-gray-300 rounded w-3/4 mb-2"></div>
70
+ {/* Message preview skeleton */}
71
+ <div className="h-3 bg-gray-200 rounded w-full"></div>
72
+ </div>
73
+ <div className="flex flex-col items-end space-y-1">
74
+ {/* Time skeleton */}
75
+ <div className="h-3 bg-gray-200 rounded w-12"></div>
76
+ {/* Badge skeleton */}
77
+ <div className="h-4 w-4 bg-gray-300 rounded-full"></div>
78
+ </div>
79
+ </div>
80
+ ))}
81
+ </div>
82
+ </div>
83
+
84
+ {/* Main Content Area Skeleton */}
85
+ <div className="flex-1 min-w-0 overflow-hidden">
86
+ <div className="flex h-full">
87
+ {/* Chat content skeleton */}
88
+ <div className="flex-1 flex flex-col">
89
+ {/* Header skeleton */}
90
+ <div className="px-6 py-4 border-b border-gray-200 bg-white flex-shrink-0">
91
+ <div className="flex items-center justify-between">
92
+ <div className="h-6 bg-gray-300 rounded w-32"></div>
93
+ <div className="h-8 bg-gray-300 rounded w-20"></div>
94
+ </div>
95
+ </div>
96
+
97
+ {/* Messages area skeleton */}
98
+ <div className="flex-1 p-4 space-y-4 overflow-hidden">
99
+ {Array.from({ length: 6 }).map((_, index) => (
100
+ <div key={index} className={`flex ${index % 2 === 0 ? 'justify-start' : 'justify-end'}`}>
101
+ <div
102
+ className={`flex items-start space-x-2 max-w-xs lg:max-w-md ${
103
+ index % 2 === 0 ? '' : 'flex-row-reverse space-x-reverse'
104
+ }`}
105
+ >
106
+ {index % 2 === 0 && (
107
+ <div className="h-8 w-8 bg-gray-300 rounded-full flex-shrink-0"></div>
108
+ )}
109
+ <div
110
+ className={`px-4 py-2 rounded-lg ${
111
+ index % 2 === 0 ? 'bg-gray-200' : 'bg-gray-300'
112
+ }`}
113
+ >
114
+ <div className="h-4 bg-gray-400 rounded w-32 mb-1"></div>
115
+ <div className="h-3 bg-gray-400 rounded w-20"></div>
116
+ </div>
117
+ </div>
118
+ </div>
119
+ ))}
120
+ </div>
121
+
122
+ {/* Message input skeleton */}
123
+ <div className="p-4 border-t border-gray-200 bg-white">
124
+ <div className="flex items-center space-x-2">
125
+ <div className="h-10 bg-gray-300 rounded-full w-10"></div>
126
+ <div className="flex-1 h-10 bg-gray-300 rounded-lg"></div>
127
+ <div className="h-10 w-10 bg-gray-300 rounded-full"></div>
128
+ </div>
129
+ </div>
130
+ </div>
131
+
132
+ {/* Right Sidebar Skeleton - Desktop only, conditionally rendered */}
133
+ {showRightSidebar && (
134
+ <div className="hidden xl:block w-72 lg:w-80 xl:w-96 border-l border-gray-200 bg-white flex-shrink-0">
135
+ <div className="p-4">
136
+ {/* Right sidebar header */}
137
+ <div className="h-6 bg-gray-300 rounded w-24 mb-4"></div>
138
+
139
+ {/* Right sidebar content */}
140
+ <div className="space-y-3">
141
+ {Array.from({ length: 4 }).map((_, index) => (
142
+ <div key={index} className="p-3 border border-gray-200 rounded-lg">
143
+ <div className="h-4 bg-gray-300 rounded w-3/4 mb-2"></div>
144
+ <div className="h-3 bg-gray-200 rounded w-full mb-1"></div>
145
+ <div className="h-3 bg-gray-200 rounded w-2/3"></div>
146
+ </div>
147
+ ))}
148
+ </div>
149
+ </div>
150
+ </div>
151
+ )}
152
+ </div>
153
+ </div>
154
+ </div>
155
+ ));
156
+
157
+ const TailwindSpinner = React.memo(() => (
158
+ <div className="flex items-center justify-center min-h-screen">
159
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
160
+ </div>
161
+ ));
162
+
163
+ interface TailwindAlertProps {
164
+ children: React.ReactNode;
165
+ }
166
+
167
+ const TailwindAlert = React.memo(({ children }: TailwindAlertProps) => (
168
+ <div className="flex items-center justify-center min-h-screen">
169
+ <div
170
+ className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative max-w-md mx-auto"
171
+ role="alert"
172
+ >
173
+ <span className="block sm:inline">{children}</span>
174
+ </div>
175
+ </div>
176
+ ));
177
+
178
+ interface InboxWithLoaderProps {
179
+ channelFilters?: Record<string, any>;
180
+ channelRole?: string;
181
+ supportServices?: boolean;
182
+ pathPrefix?: string;
183
+ orgName?: string;
184
+ [key: string]: any; // Allow other props to be passed through to Inbox
185
+ }
186
+
187
+ const InboxWithLoader = (props: InboxWithLoaderProps) => {
188
+ const { channelFilters: channelFilterProp, channelRole: channelRoleProp, supportServices, pathPrefix } = props;
189
+ const { orgName, channelRole: channelRoleParam } = useParams();
190
+ const location = useLocation();
191
+ const urlParams = location?.search ? new URLSearchParams(location.search) : null;
192
+ const template = urlParams?.get('template');
193
+ const channelRole = channelRoleParam || channelRoleProp;
194
+ console.log('template', template);
195
+
196
+ // Create new props object with orgName instead of mutating original props
197
+ const inboxProps = useMemo(
198
+ () => ({
199
+ ...props,
200
+ orgName: orgName || '',
201
+ pathPrefix: pathPrefix || '',
202
+ }),
203
+ [props, orgName, pathPrefix],
204
+ );
205
+
206
+ const { id: pathChannelId } = useParams();
207
+
208
+ // Enhanced query variables with better filtering and stable references
209
+ const channelsQueryVariables = useMemo(() => {
210
+ const channelFilters = { ...channelFilterProp };
211
+ const channelType = channelFilters?.type ?? RoomType.Direct;
212
+ const baseFilters = {
213
+ ...channelFilters,
214
+ type: supportServices ? [channelType, RoomType.Service] : channelType,
215
+ };
216
+
217
+ return queryParamsGenerator({
218
+ role: channelRole,
219
+ criteria: baseFilters,
220
+ supportServices,
221
+ orgName: orgName || '',
222
+ }).variable1;
223
+ }, [channelRole, channelFilterProp, supportServices, orgName]);
224
+
225
+ const messagesQueryVariables = useMemo(
226
+ () => ({
227
+ channelId: pathChannelId?.toString(),
228
+ parentId: null,
229
+ limit: MESSAGES_PER_PAGE,
230
+ }),
231
+ [pathChannelId],
232
+ );
233
+
234
+ const channelDetailQueryVariables = useMemo(
235
+ () => ({
236
+ id: pathChannelId?.toString(),
237
+ }),
238
+ [pathChannelId],
239
+ );
240
+
241
+ // Enhanced Apollo queries with better cache policies and error handling
242
+ const channelsQuery = useGetChannelsByUserQuery({
243
+ variables: channelsQueryVariables,
244
+ fetchPolicy: 'cache-and-network', // Better for real-time updates
245
+ errorPolicy: 'all',
246
+ notifyOnNetworkStatusChange: false,
247
+ returnPartialData: true,
248
+ // Add context for better cache management
249
+ context: {
250
+ cacheKey: 'channels-list',
251
+ },
252
+ });
253
+
254
+ const messagesQuery = useMessagesQuery({
255
+ variables: messagesQueryVariables,
256
+ skip: !pathChannelId,
257
+ fetchPolicy: 'cache-and-network', // Better for real-time messaging
258
+ errorPolicy: 'all',
259
+ notifyOnNetworkStatusChange: true,
260
+ returnPartialData: true,
261
+ // Disable polling to allow subscriptions to work properly
262
+ pollInterval: 0,
263
+ // Add context for better cache management
264
+ context: {
265
+ cacheKey: 'messages-list',
266
+ },
267
+ });
268
+
269
+ const channelDetailQuery = useViewChannelDetailQuery({
270
+ variables: channelDetailQueryVariables,
271
+ skip: !pathChannelId,
272
+ fetchPolicy: 'cache-first', // Channel details don't change often
273
+ errorPolicy: 'all',
274
+ notifyOnNetworkStatusChange: false, // No need for real-time updates
275
+ returnPartialData: true,
276
+ // Add context for better cache management
277
+ context: {
278
+ cacheKey: 'channel-detail',
279
+ },
280
+ });
281
+
282
+ // Enhanced error handling with retry logic
283
+ const handleRetry = useCallback(() => {
284
+ if (channelsQuery.error) {
285
+ channelsQuery.refetch();
286
+ }
287
+ if (messagesQuery.error) {
288
+ messagesQuery.refetch();
289
+ }
290
+ if (channelDetailQuery.error) {
291
+ channelDetailQuery.refetch();
292
+ }
293
+ }, [channelsQuery, messagesQuery, channelDetailQuery]);
294
+
295
+ // Create loader data array for Inbox component with better error handling
296
+ const loaderData = useMemo(
297
+ () => [channelsQuery, messagesQuery, channelDetailQuery],
298
+ [channelsQuery, messagesQuery, channelDetailQuery],
299
+ );
300
+
301
+ // Enhanced loading states with better UX
302
+ if (channelsQuery.loading && !pathChannelId && !channelsQuery.data) {
303
+ return <InboxSkeleton showRightSidebar={false} />;
304
+ }
305
+
306
+ // Show skeleton during initial channel loading
307
+ if (
308
+ pathChannelId &&
309
+ (messagesQuery.loading || channelDetailQuery.loading) &&
310
+ !messagesQuery.data &&
311
+ !channelDetailQuery.data
312
+ ) {
313
+ return <InboxSkeleton showRightSidebar={true} />;
314
+ }
315
+
316
+ // Enhanced error handling with retry option
317
+ if (channelsQuery.error && !channelsQuery.data) {
318
+ return (
319
+ <div className="flex flex-col items-center justify-center min-h-screen space-y-4">
320
+ <TailwindAlert>Error loading channels: {channelsQuery.error.message}</TailwindAlert>
321
+ <button
322
+ onClick={handleRetry}
323
+ className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
324
+ >
325
+ Retry
326
+ </button>
327
+ </div>
328
+ );
329
+ }
330
+
331
+ // Handle individual query errors gracefully
332
+ if (messagesQuery.error && !messagesQuery.data && pathChannelId) {
333
+ console.warn('Messages query error:', messagesQuery.error);
334
+ }
335
+
336
+ if (channelDetailQuery.error && !channelDetailQuery.data && pathChannelId) {
337
+ console.warn('Channel detail query error:', channelDetailQuery.error);
338
+ }
339
+
340
+ // Conditional rendering based on template parameter
341
+ if (template === '1') {
342
+ return <AiInbox data={loaderData} {...inboxProps} />;
343
+ } else if (template === '2') {
344
+ return <InboxTemplate1 data={loaderData} {...inboxProps} />;
345
+ } else if (template === '3') {
346
+ return <InboxTemplate2 data={loaderData} {...inboxProps} />;
347
+ } else {
348
+ // Default fallback to Inbox
349
+ return <Inbox data={loaderData} {...inboxProps} />;
350
+ }
351
+ };
352
+
353
+ // Display name for debugging
354
+ InboxWithLoader.displayName = 'InboxWithLoader';
355
+
356
+ export default React.memo(InboxWithLoader);
@@ -0,0 +1,168 @@
1
+ import React from 'react';
2
+ import { useNavigate } from '@remix-run/react';
3
+ import { RoomType } from 'common';
4
+ import { InputComponent } from '../components/InboxMessage';
5
+ import { objectId } from '@messenger-box/core';
6
+ import { useAddChannelMutation, useSendMessagesMutation } from 'common/graphql';
7
+
8
+ const TailwindOverlaySpinner = React.memo(() => (
9
+ <div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-30">
10
+ <div className="animate-spin rounded-full h-10 w-10 border-2 border-white border-t-transparent"></div>
11
+ </div>
12
+ ));
13
+
14
+ const AiLandingInput: React.FC = () => {
15
+ const [addChannel] = useAddChannelMutation();
16
+ const [sendMessage] = useSendMessagesMutation();
17
+ const navigate = useNavigate();
18
+ const [isCreatingChannel, setIsCreatingChannel] = React.useState(false);
19
+
20
+ return (
21
+ <div className="flex items-center justify-center min-h-screen bg-gray-50">
22
+ <div className="w-full max-w-2xl mx-4">
23
+ <div className="bg-white rounded-lg shadow-lg p-6">
24
+ <div className="text-center mb-6">
25
+ <h3 className="text-xl font-semibold text-gray-700 mb-2">What would you like to build?</h3>
26
+ <p className="text-gray-500">Describe your idea and I'll help you create it step by step.</p>
27
+ </div>
28
+ <InputComponent
29
+ handleSend={async (message: string, files: File[]) => {
30
+ console.log('Message sent without channel:', message, files);
31
+ setIsCreatingChannel(true);
32
+ const id = objectId();
33
+ addChannel({
34
+ variables: {
35
+ name: `AI-Assistant-${id}`,
36
+ type: RoomType.Aiassistant,
37
+ description: 'AI Assistant',
38
+ },
39
+ onCompleted: (data: any) => {
40
+ console.log('Channel created:', data);
41
+ if (!data.createChannel) {
42
+ setIsCreatingChannel(false);
43
+ return;
44
+ }
45
+ const createdId = data.createChannel.id;
46
+ sendMessage({
47
+ variables: {
48
+ channelId: createdId,
49
+ content: message,
50
+ },
51
+ onCompleted: () => {
52
+ navigate(`/ai-messenger/app?id=${createdId}`, { replace: true });
53
+ setIsCreatingChannel(false);
54
+ },
55
+ onError: (error: any) => {
56
+ console.error('Error sending message:', error);
57
+ setIsCreatingChannel(false);
58
+ },
59
+ });
60
+ },
61
+ onError: (error: any) => {
62
+ console.error('Error creating channel:', error);
63
+ setIsCreatingChannel(false);
64
+ },
65
+ });
66
+ }}
67
+ placeholder="Type your message here..."
68
+ />
69
+ <div className="mt-2">
70
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
71
+ <div className="space-y-2">
72
+ <div className="relative">
73
+ <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
74
+ <div className="w-5 h-5 bg-purple-500 rounded-full flex items-center justify-center">
75
+ <span className="text-white text-xs font-bold">N</span>
76
+ </div>
77
+ </div>
78
+ <select className="block w-full pl-10 pr-10 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 bg-white">
79
+ <option value="nextjs">Next.js</option>
80
+ <option value="vuejs">Vue.js</option>
81
+ <option value="vite-remix">Vite with Remix</option>
82
+ </select>
83
+ <div className="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
84
+ <svg
85
+ className="h-5 w-5 text-gray-400"
86
+ fill="none"
87
+ stroke="currentColor"
88
+ viewBox="0 0 24 24"
89
+ >
90
+ <path
91
+ strokeLinecap="round"
92
+ strokeLinejoin="round"
93
+ strokeWidth={2}
94
+ d="M19 9l-7 7-7-7"
95
+ />
96
+ </svg>
97
+ </div>
98
+ </div>
99
+ </div>
100
+ <div className="space-y-2">
101
+ <div className="relative">
102
+ <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
103
+ <div className="w-5 h-5 bg-pink-500 rounded-full flex items-center justify-center">
104
+ <svg className="w-3 h-3 text-white" fill="currentColor" viewBox="0 0 20 20">
105
+ <path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
106
+ </svg>
107
+ </div>
108
+ </div>
109
+ <select className="block w-full pl-10 pr-10 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-pink-500 focus:border-pink-500 bg-white">
110
+ <option value="claude-3-5-sonnet">Claude 3.5 Sonnet</option>
111
+ <option value="claude-3-5-haiku">Claude 3.5 Haiku</option>
112
+ <option value="claude-3-opus">Claude 3 Opus</option>
113
+ <option value="claude-3-sonnet">Claude 3 Sonnet</option>
114
+ <option value="claude-3-haiku">Claude 3 Haiku</option>
115
+ </select>
116
+ <div className="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
117
+ <svg
118
+ className="h-5 w-5 text-gray-400"
119
+ fill="none"
120
+ stroke="currentColor"
121
+ viewBox="0 0 24 24"
122
+ >
123
+ <path
124
+ strokeLinecap="round"
125
+ strokeLinejoin="round"
126
+ strokeWidth={2}
127
+ d="M19 9l-7 7-7-7"
128
+ />
129
+ </svg>
130
+ </div>
131
+ </div>
132
+ </div>
133
+ <div className="space-y-2">
134
+ <div className="relative">
135
+ <select className="block w-full pr-10 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white">
136
+ <option value="">API Key</option>
137
+ <option value="saved-key-1">••••••••••••</option>
138
+ <option value="saved-key-2">••••••••••••</option>
139
+ </select>
140
+ <div className="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
141
+ <svg
142
+ className="h-5 w-5 text-gray-400"
143
+ fill="none"
144
+ stroke="currentColor"
145
+ viewBox="0 0 24 24"
146
+ >
147
+ <path
148
+ strokeLinecap="round"
149
+ strokeLinejoin="round"
150
+ strokeWidth={2}
151
+ d="M19 9l-7 7-7-7"
152
+ />
153
+ </svg>
154
+ </div>
155
+ </div>
156
+ </div>
157
+ </div>
158
+ </div>
159
+ </div>
160
+ </div>
161
+ {isCreatingChannel && <TailwindOverlaySpinner />}
162
+ </div>
163
+ );
164
+ };
165
+
166
+ AiLandingInput.displayName = 'AiLandingInput';
167
+
168
+ export default React.memo(AiLandingInput);
@@ -8,10 +8,11 @@ import {
8
8
  } from 'common/graphql';
9
9
  import { useUploadFiles } from '@messenger-box/platform-client';
10
10
  import { IFileInfo, RoomType, PostTypeEnum } from 'common';
11
- import { useSelector } from 'react-redux';
11
+ import { useSelector, shallowEqual } from 'react-redux';
12
12
  import { useNavigate, useParams } from '@remix-run/react';
13
13
  import { LeftSidebar, MessageInput, Messages, RightSidebar } from '../components';
14
- import { userSelector } from '@adminide-stack/user-auth0-client';
14
+ import { Store, userSelector } from '@adminide-stack/user-auth0-client';
15
+ import { IUserState } from '@adminide-stack/core';
15
16
  import { config } from '../config';
16
17
  import { applyFooterStyles } from './apply-footer-styles';
17
18
  import { objectId } from '@messenger-box/core';
@@ -172,7 +173,9 @@ const Inbox = (props: InboxProps) => {
172
173
  const isDesktopView = useMediaQuery('(min-width: 1025px)');
173
174
  const isLargeDesktopView = useMediaQuery('(min-width: 1440px)');
174
175
  const isSmallScreen = useMediaQuery('(max-width: 900px)');
175
- const auth = useSelector(userSelector);
176
+ // const auth = useSelector(userSelector);
177
+ const auth: any = useSelector<Store.Auth, IUserState>(userSelector, shallowEqual);
178
+ // const user = useSelector((state: any) => state.user, shallowEqual);
176
179
 
177
180
  // Data destructuring from Apollo queries
178
181
  const GetChannelsByUserQuery = data?.[0];
@@ -235,8 +238,8 @@ const Inbox = (props: InboxProps) => {
235
238
  return title || 'Direct Message';
236
239
  }
237
240
 
238
- if (members.length === 1 && members[0].user.id === currentUser?.id) {
239
- if (members[0].user?.givenName && members[0].user?.familyName) {
241
+ if (type === RoomType.Direct && members?.length === 1) {
242
+ if (members[0].user?.givenName && members[0]?.user?.familyName) {
240
243
  return `${members[0].user?.givenName} ${members[0].user?.familyName}`;
241
244
  }
242
245
  return members[0].user?.givenName || members[0].user?.familyName || 'Direct Message';
@@ -0,0 +1,58 @@
1
+ import React, { useMemo, useCallback } from 'react';
2
+ import { useParams, useLocation } from '@remix-run/react';
3
+ import { RoomType } from 'common';
4
+ import { config } from '../config';
5
+ import { AIAgent } from '../components/AIAgent';
6
+ import { useSelector, shallowEqual } from 'react-redux';
7
+ import { Store, userSelector } from '@adminide-stack/user-auth0-client';
8
+ import { IUserState } from '@adminide-stack/core';
9
+
10
+ // Enhanced query parameters generator with better typing and flexibility
11
+ export const queryParamsGenerator = (params: {
12
+ role?: string;
13
+ criteria?: Record<string, any>;
14
+ supportServices?: boolean;
15
+ orgName?: string;
16
+ }) => ({
17
+ variable1: {
18
+ role: params.role,
19
+ criteria: {
20
+ ...params.criteria,
21
+ ...(params.orgName && { orgName: params.orgName }),
22
+ },
23
+ supportServices: params.supportServices ? true : false,
24
+ supportServiceCriteria: params.supportServices
25
+ ? {
26
+ type: RoomType.Service,
27
+ }
28
+ : undefined,
29
+ orderBy: {
30
+ lastPostAt: 'desc',
31
+ },
32
+ },
33
+ });
34
+
35
+ interface InboxWithAiLoaderOutletProps {
36
+ channelFilters?: Record<string, any>;
37
+ channelRole?: string;
38
+ supportServices?: boolean;
39
+ pathPrefix?: string;
40
+ orgName?: string;
41
+ [key: string]: any; // Allow other props to be passed through to Inbox
42
+ }
43
+
44
+ const InboxWithAiLoaderOutlet = (props: InboxWithAiLoaderOutletProps) => {
45
+ const { channelFilters: channelFilterProp, channelRole: channelRoleProp, supportServices, pathPrefix } = props;
46
+ const { orgName, channelRole: channelRoleParam } = useParams();
47
+ const location = useLocation();
48
+ const urlParams = location?.search ? new URLSearchParams(location.search) : null;
49
+ const channelId = urlParams?.get('id');
50
+ const user: any = useSelector<Store.Auth, IUserState>(userSelector, shallowEqual);
51
+
52
+ return <AIAgent channelId={channelId} placeholder="Ask me anything..." className="h-full" currentUser={user} />;
53
+ };
54
+
55
+ // Display name for debugging
56
+ InboxWithAiLoaderOutlet.displayName = 'InboxWithAiLoaderOutlet';
57
+
58
+ export default React.memo(InboxWithAiLoaderOutlet);
@@ -0,0 +1,35 @@
1
+ import React, { useMemo, useCallback } from 'react';
2
+ import Inbox from '../templates/InboxWithAi';
3
+
4
+ interface InboxContainerProps {
5
+ channelId: string;
6
+ channelFilters?: Record<string, any>;
7
+ channelRole?: string;
8
+ supportServices?: boolean;
9
+ orgName?: string;
10
+ [key: string]: any;
11
+ }
12
+
13
+ const InboxSkeleton = React.memo(({ showRightSidebar = false }: { showRightSidebar?: boolean }) => (
14
+ <div
15
+ className="h-full border-t border-gray-300 flex overflow-hidden animate-pulse"
16
+ style={{ height: '100vh !important' }}
17
+ >
18
+ <div className="flex-1 min-w-0 bg-white border-r border-gray-300"></div>
19
+ {showRightSidebar && <div className="w-80 border-l border-gray-200 bg-white flex-shrink-0"></div>}
20
+ </div>
21
+ ));
22
+
23
+ const InboxContainer: React.FC<InboxContainerProps> = (props) => {
24
+ const { channelId, channelFilters: channelFilterProp, channelRole, supportServices, orgName } = props;
25
+
26
+ if (!channelId) {
27
+ return <InboxSkeleton showRightSidebar={true} />;
28
+ }
29
+
30
+ return <Inbox {...props} />;
31
+ };
32
+
33
+ InboxContainer.displayName = 'InboxContainer';
34
+
35
+ export default React.memo(InboxContainer);