keystone-design-bootstrap 1.0.39 → 1.0.40

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keystone-design-bootstrap",
3
- "version": "1.0.39",
3
+ "version": "1.0.40",
4
4
  "description": "Keystone Design Bootstrap - Sections, Elements, and Theme System for customer websites",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -7,7 +7,7 @@ import { cx } from '../../utils/cx';
7
7
 
8
8
  interface Message {
9
9
  id: string;
10
- body: string | null;
10
+ body: string;
11
11
  sender_type: 'contact' | 'agent' | 'human';
12
12
  sender_display_name: string;
13
13
  created_at: string;
@@ -112,36 +112,32 @@ export function ChatWidget({
112
112
  // Poll for agent reply (simpler than WebSockets for public widget)
113
113
  const pollForAgentReply = () => {
114
114
  setWaitingForReply(true);
115
-
116
- const initialCount = messages.length;
115
+
117
116
  let attempts = 0;
118
117
  const maxAttempts = 30; // 30 seconds max
119
-
120
- console.log(`[ChatWidget] Starting poll for agent reply (initial count: ${initialCount})`);
121
-
118
+
122
119
  const pollInterval = setInterval(async () => {
123
120
  attempts++;
124
-
121
+
125
122
  try {
126
123
  const newMessages = await loadMessages();
127
- console.log(`[ChatWidget] Poll attempt ${attempts}: got ${newMessages.length} messages (initial: ${initialCount})`);
128
-
129
- // Check if we got a new agent message with actual content (ignore pending placeholder with empty body)
130
- if (newMessages.length > initialCount) {
131
- const latestMessage = newMessages[newMessages.length - 1];
132
- console.log(`[ChatWidget] Poll attempt ${attempts}: latest sender_type=${latestMessage.sender_type}, body=${latestMessage.body != null ? `${String(latestMessage.body).substring(0, 50)}` : 'null'}`);
133
124
 
134
- if (latestMessage.sender_type === 'agent' && (latestMessage.body != null && String(latestMessage.body).trim() !== '')) {
135
- console.log('[ChatWidget] Received agent reply with content');
136
- clearInterval(pollInterval);
137
- setWaitingForReply(false);
138
- setIsLoading(false);
139
- }
125
+ // Clear as soon as the latest message is an agent reply with content (don't rely on count increase can fail at list cap or with optimistic updates)
126
+ const latest = newMessages[newMessages.length - 1];
127
+ const hasAgentReplyWithBody =
128
+ latest?.sender_type === 'agent' &&
129
+ latest?.body != null &&
130
+ String(latest.body).trim() !== '';
131
+
132
+ if (hasAgentReplyWithBody) {
133
+ clearInterval(pollInterval);
134
+ setWaitingForReply(false);
135
+ setIsLoading(false);
136
+ return;
140
137
  }
141
-
138
+
142
139
  // Stop polling after max attempts
143
140
  if (attempts >= maxAttempts) {
144
- console.warn('[ChatWidget] ⚠ Polling timeout - no reply received after 30s');
145
141
  clearInterval(pollInterval);
146
142
  setWaitingForReply(false);
147
143
  setIsLoading(false);
@@ -188,8 +184,7 @@ export function ChatWidget({
188
184
 
189
185
  // Message sent successfully
190
186
  if (result.data?.job_id) {
191
- // Sync with server so outbound message is in the list, then poll for reply
192
- await loadMessages();
187
+ // Job is processing - poll for the reply
193
188
  pollForAgentReply();
194
189
  } else if (result.data?.status === 'agent_unavailable' || result.data?.status === 'no_auto_reply') {
195
190
  // No agent reply expected
@@ -310,14 +305,10 @@ export function ChatWidget({
310
305
  Start a conversation! We're here to help.
311
306
  </li>
312
307
  )}
313
- {/* Don't show pending agent messages (empty body) - keeps typing indicator until real reply */}
314
- {(() => {
315
- const toShow = messages.filter(
316
- (m) => m.sender_type !== 'agent' || (m.body != null && String(m.body).trim() !== '')
317
- );
318
- return toShow.map((message, index) => {
308
+
309
+ {messages.map((message, index) => {
319
310
  const isUser = message.sender_type === 'contact';
320
- const prevMessage = index > 0 ? toShow[index - 1] : null;
311
+ const prevMessage = index > 0 ? messages[index - 1] : null;
321
312
  const showAvatar = !isUser && (!prevMessage || prevMessage.sender_type === 'contact');
322
313
 
323
314
  return (
@@ -374,13 +365,12 @@ export function ChatWidget({
374
365
  : "rounded-tl-none bg-secondary text-primary ring-secondary"
375
366
  )}
376
367
  >
377
- {message.body ?? ''}
368
+ {message.body}
378
369
  </div>
379
370
  </article>
380
371
  </li>
381
372
  );
382
- });
383
- })()}
373
+ })}
384
374
 
385
375
  {/* Typing indicator */}
386
376
  {waitingForReply && (