rio-assist-widget 0.1.14 → 0.1.18

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": "rio-assist-widget",
3
- "version": "0.1.14",
3
+ "version": "0.1.18",
4
4
  "description": "Web Component do painel lateral Rio Insight, pronto para ser embutido em qualquer projeto.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -286,11 +286,17 @@ export const conversationsPanelStyles = css`
286
286
  height: 16px;
287
287
  }
288
288
 
289
- .conversation-loading {
290
- font-size: 13px;
291
- color: #4b5b68;
292
- padding: 6px 12px 2px;
293
- }
289
+ .conversation-loading {
290
+ font-size: 13px;
291
+ color: #4b5b68;
292
+ padding: 6px 12px 2px;
293
+ }
294
+
295
+ .conversation-error {
296
+ font-size: 13px;
297
+ color: #a33c3c;
298
+ padding: 6px 12px 2px;
299
+ }
294
300
 
295
301
  .new-conversation-cta {
296
302
  overflow: hidden;
@@ -168,18 +168,21 @@ const renderConversationSurface = (
168
168
  </div>
169
169
 
170
170
  <div
171
- class=${classMap({
172
- 'conversation-list-wrapper': true,
173
- 'conversation-list-wrapper--sidebar': isSidebar,
174
- })}
175
- >
176
- ${component.conversationHistoryLoading
177
- ? html`<div class="conversation-loading">Carregando conversas...</div>`
178
- : null}
179
- ${list}
180
- ${isSidebar
181
- ? html`
182
- <div
171
+ class=${classMap({
172
+ 'conversation-list-wrapper': true,
173
+ 'conversation-list-wrapper--sidebar': isSidebar,
174
+ })}
175
+ >
176
+ ${component.conversationHistoryLoading
177
+ ? html`<div class="conversation-loading">Carregando conversas...</div>`
178
+ : null}
179
+ ${component.conversationHistoryError
180
+ ? html`<div class="conversation-error">${component.conversationHistoryError}</div>`
181
+ : null}
182
+ ${list}
183
+ ${isSidebar
184
+ ? html`
185
+ <div
183
186
  class=${classMap({
184
187
  'conversation-scrollbar': true,
185
188
  'conversation-scrollbar--visible':
@@ -22,6 +22,60 @@ const baseStyles = css`
22
22
  border-radius: 999px;
23
23
  transition: transform 0.2s ease, box-shadow 0.2s ease;
24
24
  }
25
+
26
+ .dialog-overlay {
27
+ position: fixed;
28
+ inset: 0;
29
+ background: rgba(0, 0, 0, 0.35);
30
+ display: grid;
31
+ place-items: center;
32
+ z-index: 2147484000;
33
+ pointer-events: auto;
34
+ }
35
+
36
+ .dialog {
37
+ width: min(360px, calc(100% - 32px));
38
+ background: #fff;
39
+ border-radius: 12px;
40
+ box-shadow: 0 14px 32px rgba(0, 0, 0, 0.22);
41
+ padding: 20px;
42
+ display: flex;
43
+ flex-direction: column;
44
+ gap: 16px;
45
+ }
46
+
47
+ .dialog__message {
48
+ margin: 0;
49
+ font-size: 16px;
50
+ color: #1f2f36;
51
+ }
52
+
53
+ .dialog__actions {
54
+ display: flex;
55
+ justify-content: flex-end;
56
+ gap: 10px;
57
+ }
58
+
59
+ .dialog__button {
60
+ min-width: 96px;
61
+ height: 36px;
62
+ padding: 0 14px;
63
+ border-radius: 8px;
64
+ border: 1px solid transparent;
65
+ font-weight: 600;
66
+ transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
67
+ }
68
+
69
+ .dialog__button--ghost {
70
+ background: #fff;
71
+ border-color: #c7d0d9;
72
+ color: #1f2f36;
73
+ }
74
+
75
+ .dialog__button--danger {
76
+ background: #008b9a;
77
+ color: #fff;
78
+ }
25
79
  `;
26
80
 
27
81
  export const widgetStyles = [
@@ -16,6 +16,25 @@ export const renderRioAssist = (component: RioAssistWidget) => {
16
16
  ${renderFloatingButton(component)}
17
17
  ${renderMiniPanel(component)}
18
18
  ${component.isFullscreen ? renderFullscreen(component) : null}
19
+ ${component.deleteConversationTarget
20
+ ? html`
21
+ <div class="dialog-overlay" role="dialog" aria-modal="true">
22
+ <div class="dialog">
23
+ <p class="dialog__message">Deseja realmente excluir essa conversa?</p>
24
+ <div class="dialog__actions">
25
+ <button type="button" class="dialog__button dialog__button--ghost" @click=${() =>
26
+ component.cancelDeleteConversation()}>
27
+ Cancelar
28
+ </button>
29
+ <button type="button" class="dialog__button dialog__button--danger" @click=${() =>
30
+ component.confirmDeleteConversation()}>
31
+ Excluir
32
+ </button>
33
+ </div>
34
+ </div>
35
+ </div>
36
+ `
37
+ : null}
19
38
  </div>
20
39
  `;
21
40
  };
@@ -25,6 +25,12 @@ type ConversationItem = {
25
25
  updatedAt: string;
26
26
  };
27
27
 
28
+ type ConversationDeleteTarget = {
29
+ id: string;
30
+ title: string;
31
+ index: number;
32
+ };
33
+
28
34
  export type HeaderActionConfig = {
29
35
  id?: string;
30
36
  iconUrl: string;
@@ -58,6 +64,8 @@ export class RioAssistWidget extends LitElement {
58
64
  conversations: { state: true },
59
65
  conversationHistoryLoading: { type: Boolean, state: true },
60
66
  activeConversationTitle: { state: true },
67
+ conversationHistoryError: { type: String, state: true },
68
+ deleteConversationTarget: { attribute: false },
61
69
  headerActions: { attribute: false },
62
70
  homeUrl: { type: String, attribute: 'data-home-url' },
63
71
  };
@@ -106,6 +114,10 @@ export class RioAssistWidget extends LitElement {
106
114
 
107
115
  conversationHistoryLoading = false;
108
116
 
117
+ conversationHistoryError = '';
118
+
119
+ deleteConversationTarget: ConversationDeleteTarget | null = null;
120
+
109
121
  private refreshConversationsAfterResponse = false;
110
122
 
111
123
  activeConversationTitle: string | null = null;
@@ -355,18 +367,25 @@ export class RioAssistWidget extends LitElement {
355
367
  this.conversationMenuId = null;
356
368
  }
357
369
  }
358
-
370
+
359
371
  handleConversationAction(action: 'rename' | 'delete', id: string) {
360
372
  this.conversationMenuId = null;
361
- const conversation = this.conversations.find((item) => item.id === id);
362
- if (!conversation) {
373
+ const conversationIndex = this.conversations.findIndex((item) => item.id === id);
374
+ if (conversationIndex === -1) {
363
375
  return;
364
- }
365
-
366
- const message = `${
367
- action === 'rename' ? 'Renomear' : 'Excluir'
368
- } "${conversation.title}"`;
369
- console.info(`[Mock] ${message}`);
376
+ }
377
+
378
+ const conversation = this.conversations[conversationIndex];
379
+ if (action === 'delete') {
380
+ this.deleteConversationTarget = {
381
+ id: conversation.id,
382
+ title: conversation.title,
383
+ index: conversationIndex,
384
+ };
385
+ return;
386
+ }
387
+
388
+ this.dispatchConversationAction('rename', conversation, conversationIndex);
370
389
  }
371
390
 
372
391
  handleHomeNavigation() {
@@ -389,6 +408,96 @@ export class RioAssistWidget extends LitElement {
389
408
  }
390
409
  }
391
410
 
411
+ applyConversationRename(id: string, newTitle: string) {
412
+ if (!id || !newTitle) {
413
+ return;
414
+ }
415
+
416
+ let changed = false;
417
+ this.conversations = this.conversations.map((conversation) => {
418
+ if (conversation.id === id) {
419
+ changed = true;
420
+ return { ...conversation, title: newTitle };
421
+ }
422
+ return conversation;
423
+ });
424
+
425
+ if (!changed) {
426
+ return;
427
+ }
428
+
429
+ if (this.currentConversationId === id) {
430
+ this.activeConversationTitle = newTitle;
431
+ }
432
+ }
433
+
434
+ applyConversationDeletion(id: string) {
435
+ if (!id) {
436
+ return;
437
+ }
438
+
439
+ const wasActive = this.currentConversationId === id;
440
+ const next = this.conversations.filter((conversation) => conversation.id !== id);
441
+
442
+ if (next.length === this.conversations.length) {
443
+ return;
444
+ }
445
+
446
+ this.conversations = next;
447
+
448
+ if (wasActive) {
449
+ this.currentConversationId = null;
450
+ this.activeConversationTitle = null;
451
+ this.messages = [];
452
+ }
453
+ }
454
+
455
+ confirmDeleteConversation() {
456
+ const target = this.deleteConversationTarget;
457
+ if (!target) {
458
+ return;
459
+ }
460
+
461
+ this.dispatchConversationAction('delete', { id: target.id, title: target.title }, target.index);
462
+ this.deleteConversationTarget = null;
463
+ }
464
+
465
+ cancelDeleteConversation() {
466
+ this.deleteConversationTarget = null;
467
+ }
468
+
469
+ private dispatchConversationAction(
470
+ action: 'rename' | 'delete',
471
+ conversation: Pick<ConversationItem, 'id' | 'title'>,
472
+ index: number,
473
+ ) {
474
+ const eventName =
475
+ action === 'rename' ? 'rioassist:conversation-rename' : 'rioassist:conversation-delete';
476
+ const detail = {
477
+ id: conversation.id,
478
+ title: conversation.title,
479
+ index,
480
+ action,
481
+ };
482
+
483
+ const allowed = this.dispatchEvent(
484
+ new CustomEvent(eventName, {
485
+ detail,
486
+ bubbles: true,
487
+ composed: true,
488
+ cancelable: true,
489
+ }),
490
+ );
491
+
492
+ if (!allowed) {
493
+ return;
494
+ }
495
+
496
+ if (action === 'delete') {
497
+ this.applyConversationDeletion(conversation.id);
498
+ }
499
+ }
500
+
392
501
  handleHeaderActionClick(action: HeaderActionConfig, index: number) {
393
502
  const detail = {
394
503
  index,
@@ -428,15 +537,16 @@ export class RioAssistWidget extends LitElement {
428
537
  }
429
538
  }
430
539
 
431
- enterFullscreen() {
432
- if (this.isFullscreen) {
433
- return;
434
- }
435
-
436
- this.isFullscreen = true;
437
- this.open = false;
438
- this.showConversations = false;
439
- }
540
+ enterFullscreen() {
541
+ if (this.isFullscreen) {
542
+ return;
543
+ }
544
+
545
+ this.isFullscreen = true;
546
+ this.open = false;
547
+ this.showConversations = false;
548
+ this.requestConversationHistory();
549
+ }
440
550
 
441
551
  exitFullscreen(restorePanel: boolean) {
442
552
  if (!this.isFullscreen) {
@@ -746,10 +856,15 @@ export class RioAssistWidget extends LitElement {
746
856
  limit,
747
857
  });
748
858
 
859
+ this.conversationHistoryError = '';
749
860
  this.conversationHistoryLoading = true;
750
861
  await client.requestHistory({ conversationId, limit });
751
862
  } catch (error) {
752
863
  console.error('[RioAssist][history] erro ao solicitar historico', error);
864
+ this.conversationHistoryError =
865
+ error instanceof Error && error.message
866
+ ? error.message
867
+ : 'Nao foi possivel carregar as conversas.';
753
868
  this.conversationHistoryLoading = false;
754
869
  }
755
870
  }
@@ -813,6 +928,7 @@ export class RioAssistWidget extends LitElement {
813
928
  console.info('[RioAssist][history] payload sem itens para montar lista de conversas');
814
929
  this.conversations = [];
815
930
  this.conversationHistoryLoading = false;
931
+ this.conversationHistoryError = '';
816
932
  return;
817
933
  }
818
934
 
@@ -853,6 +969,7 @@ export class RioAssistWidget extends LitElement {
853
969
 
854
970
  this.conversations = conversations;
855
971
  this.conversationHistoryLoading = false;
972
+ this.conversationHistoryError = '';
856
973
  this.syncActiveConversationTitle();
857
974
  console.info('[RioAssist][history] conversas normalizadas', conversations);
858
975
  }