@repzo/widget-react-native 1.0.0 → 1.0.4

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 (153) hide show
  1. package/README.md +167 -74
  2. package/lib/commonjs/api/client.js +3 -1
  3. package/lib/commonjs/api/client.js.map +1 -1
  4. package/lib/commonjs/api/realtime.js +2 -0
  5. package/lib/commonjs/api/realtime.js.map +1 -1
  6. package/lib/commonjs/attachments/pickers.js +493 -0
  7. package/lib/commonjs/attachments/pickers.js.map +1 -0
  8. package/lib/commonjs/i18n.js +45 -0
  9. package/lib/commonjs/i18n.js.map +1 -1
  10. package/lib/commonjs/index.js.map +1 -1
  11. package/lib/commonjs/locales.js +21 -0
  12. package/lib/commonjs/locales.js.map +1 -1
  13. package/lib/commonjs/state/widget-store.js +256 -18
  14. package/lib/commonjs/state/widget-store.js.map +1 -1
  15. package/lib/commonjs/types.js +16 -0
  16. package/lib/commonjs/types.js.map +1 -1
  17. package/lib/commonjs/ui/WidgetProvider.js +70 -10
  18. package/lib/commonjs/ui/WidgetProvider.js.map +1 -1
  19. package/lib/commonjs/ui/components/AttachmentChips.js +135 -0
  20. package/lib/commonjs/ui/components/AttachmentChips.js.map +1 -0
  21. package/lib/commonjs/ui/components/AttachmentMenu.js +125 -0
  22. package/lib/commonjs/ui/components/AttachmentMenu.js.map +1 -0
  23. package/lib/commonjs/ui/components/ImageViewer.js +181 -0
  24. package/lib/commonjs/ui/components/ImageViewer.js.map +1 -0
  25. package/lib/commonjs/ui/components/InAppNotification.js +210 -0
  26. package/lib/commonjs/ui/components/InAppNotification.js.map +1 -0
  27. package/lib/commonjs/ui/components/TeamAvatars.js +63 -0
  28. package/lib/commonjs/ui/components/TeamAvatars.js.map +1 -0
  29. package/lib/commonjs/ui/components/icons.js +50 -0
  30. package/lib/commonjs/ui/components/icons.js.map +1 -1
  31. package/lib/commonjs/ui/screens/chat/ChatView.js +303 -24
  32. package/lib/commonjs/ui/screens/chat/ChatView.js.map +1 -1
  33. package/lib/commonjs/ui/screens/chat/ChatView.styles.js +70 -0
  34. package/lib/commonjs/ui/screens/chat/ChatView.styles.js.map +1 -1
  35. package/lib/module/api/client.js +3 -1
  36. package/lib/module/api/client.js.map +1 -1
  37. package/lib/module/api/realtime.js +2 -0
  38. package/lib/module/api/realtime.js.map +1 -1
  39. package/lib/module/attachments/pickers.js +479 -0
  40. package/lib/module/attachments/pickers.js.map +1 -0
  41. package/lib/module/i18n.js +44 -0
  42. package/lib/module/i18n.js.map +1 -1
  43. package/lib/module/index.js.map +1 -1
  44. package/lib/module/locales.js +21 -0
  45. package/lib/module/locales.js.map +1 -1
  46. package/lib/module/state/widget-store.js +256 -18
  47. package/lib/module/state/widget-store.js.map +1 -1
  48. package/lib/module/types.js +16 -0
  49. package/lib/module/types.js.map +1 -1
  50. package/lib/module/ui/WidgetProvider.js +71 -11
  51. package/lib/module/ui/WidgetProvider.js.map +1 -1
  52. package/lib/module/ui/components/AttachmentChips.js +131 -0
  53. package/lib/module/ui/components/AttachmentChips.js.map +1 -0
  54. package/lib/module/ui/components/AttachmentMenu.js +120 -0
  55. package/lib/module/ui/components/AttachmentMenu.js.map +1 -0
  56. package/lib/module/ui/components/ImageViewer.js +177 -0
  57. package/lib/module/ui/components/ImageViewer.js.map +1 -0
  58. package/lib/module/ui/components/InAppNotification.js +208 -0
  59. package/lib/module/ui/components/InAppNotification.js.map +1 -0
  60. package/lib/module/ui/components/TeamAvatars.js +59 -0
  61. package/lib/module/ui/components/TeamAvatars.js.map +1 -0
  62. package/lib/module/ui/components/icons.js +49 -0
  63. package/lib/module/ui/components/icons.js.map +1 -1
  64. package/lib/module/ui/screens/chat/ChatView.js +306 -27
  65. package/lib/module/ui/screens/chat/ChatView.js.map +1 -1
  66. package/lib/module/ui/screens/chat/ChatView.styles.js +70 -0
  67. package/lib/module/ui/screens/chat/ChatView.styles.js.map +1 -1
  68. package/lib/typescript/commonjs/api/client.d.ts +8 -2
  69. package/lib/typescript/commonjs/api/client.d.ts.map +1 -1
  70. package/lib/typescript/commonjs/api/realtime.d.ts.map +1 -1
  71. package/lib/typescript/commonjs/attachments/pickers.d.ts +81 -0
  72. package/lib/typescript/commonjs/attachments/pickers.d.ts.map +1 -0
  73. package/lib/typescript/commonjs/i18n.d.ts +23 -0
  74. package/lib/typescript/commonjs/i18n.d.ts.map +1 -1
  75. package/lib/typescript/commonjs/index.d.ts +1 -1
  76. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  77. package/lib/typescript/commonjs/locales.d.ts.map +1 -1
  78. package/lib/typescript/commonjs/state/widget-store.d.ts +40 -2
  79. package/lib/typescript/commonjs/state/widget-store.d.ts.map +1 -1
  80. package/lib/typescript/commonjs/types.d.ts +88 -1
  81. package/lib/typescript/commonjs/types.d.ts.map +1 -1
  82. package/lib/typescript/commonjs/ui/WidgetProvider.d.ts.map +1 -1
  83. package/lib/typescript/commonjs/ui/components/AttachmentChips.d.ts +16 -0
  84. package/lib/typescript/commonjs/ui/components/AttachmentChips.d.ts.map +1 -0
  85. package/lib/typescript/commonjs/ui/components/AttachmentMenu.d.ts +28 -0
  86. package/lib/typescript/commonjs/ui/components/AttachmentMenu.d.ts.map +1 -0
  87. package/lib/typescript/commonjs/ui/components/ImageViewer.d.ts +23 -0
  88. package/lib/typescript/commonjs/ui/components/ImageViewer.d.ts.map +1 -0
  89. package/lib/typescript/commonjs/ui/components/InAppNotification.d.ts +28 -0
  90. package/lib/typescript/commonjs/ui/components/InAppNotification.d.ts.map +1 -0
  91. package/lib/typescript/commonjs/ui/components/TeamAvatars.d.ts +17 -0
  92. package/lib/typescript/commonjs/ui/components/TeamAvatars.d.ts.map +1 -0
  93. package/lib/typescript/commonjs/ui/components/icons.d.ts +2 -0
  94. package/lib/typescript/commonjs/ui/components/icons.d.ts.map +1 -1
  95. package/lib/typescript/commonjs/ui/screens/chat/ChatView.d.ts +3 -2
  96. package/lib/typescript/commonjs/ui/screens/chat/ChatView.d.ts.map +1 -1
  97. package/lib/typescript/commonjs/ui/screens/chat/ChatView.styles.d.ts +69 -0
  98. package/lib/typescript/commonjs/ui/screens/chat/ChatView.styles.d.ts.map +1 -1
  99. package/lib/typescript/commonjs/ui/screens/chat/ChatView.types.d.ts +41 -2
  100. package/lib/typescript/commonjs/ui/screens/chat/ChatView.types.d.ts.map +1 -1
  101. package/lib/typescript/module/api/client.d.ts +8 -2
  102. package/lib/typescript/module/api/client.d.ts.map +1 -1
  103. package/lib/typescript/module/api/realtime.d.ts.map +1 -1
  104. package/lib/typescript/module/attachments/pickers.d.ts +81 -0
  105. package/lib/typescript/module/attachments/pickers.d.ts.map +1 -0
  106. package/lib/typescript/module/i18n.d.ts +23 -0
  107. package/lib/typescript/module/i18n.d.ts.map +1 -1
  108. package/lib/typescript/module/index.d.ts +1 -1
  109. package/lib/typescript/module/index.d.ts.map +1 -1
  110. package/lib/typescript/module/locales.d.ts.map +1 -1
  111. package/lib/typescript/module/state/widget-store.d.ts +40 -2
  112. package/lib/typescript/module/state/widget-store.d.ts.map +1 -1
  113. package/lib/typescript/module/types.d.ts +88 -1
  114. package/lib/typescript/module/types.d.ts.map +1 -1
  115. package/lib/typescript/module/ui/WidgetProvider.d.ts.map +1 -1
  116. package/lib/typescript/module/ui/components/AttachmentChips.d.ts +16 -0
  117. package/lib/typescript/module/ui/components/AttachmentChips.d.ts.map +1 -0
  118. package/lib/typescript/module/ui/components/AttachmentMenu.d.ts +28 -0
  119. package/lib/typescript/module/ui/components/AttachmentMenu.d.ts.map +1 -0
  120. package/lib/typescript/module/ui/components/ImageViewer.d.ts +23 -0
  121. package/lib/typescript/module/ui/components/ImageViewer.d.ts.map +1 -0
  122. package/lib/typescript/module/ui/components/InAppNotification.d.ts +28 -0
  123. package/lib/typescript/module/ui/components/InAppNotification.d.ts.map +1 -0
  124. package/lib/typescript/module/ui/components/TeamAvatars.d.ts +17 -0
  125. package/lib/typescript/module/ui/components/TeamAvatars.d.ts.map +1 -0
  126. package/lib/typescript/module/ui/components/icons.d.ts +2 -0
  127. package/lib/typescript/module/ui/components/icons.d.ts.map +1 -1
  128. package/lib/typescript/module/ui/screens/chat/ChatView.d.ts +3 -2
  129. package/lib/typescript/module/ui/screens/chat/ChatView.d.ts.map +1 -1
  130. package/lib/typescript/module/ui/screens/chat/ChatView.styles.d.ts +69 -0
  131. package/lib/typescript/module/ui/screens/chat/ChatView.styles.d.ts.map +1 -1
  132. package/lib/typescript/module/ui/screens/chat/ChatView.types.d.ts +41 -2
  133. package/lib/typescript/module/ui/screens/chat/ChatView.types.d.ts.map +1 -1
  134. package/metro.js +17 -32
  135. package/package.json +18 -1
  136. package/src/api/client.ts +5 -3
  137. package/src/api/realtime.ts +2 -0
  138. package/src/attachments/pickers.ts +515 -0
  139. package/src/i18n.ts +48 -0
  140. package/src/index.tsx +4 -0
  141. package/src/locales.ts +21 -0
  142. package/src/state/widget-store.ts +256 -19
  143. package/src/types.ts +95 -0
  144. package/src/ui/WidgetProvider.tsx +90 -9
  145. package/src/ui/components/AttachmentChips.tsx +135 -0
  146. package/src/ui/components/AttachmentMenu.tsx +132 -0
  147. package/src/ui/components/ImageViewer.tsx +178 -0
  148. package/src/ui/components/InAppNotification.tsx +225 -0
  149. package/src/ui/components/TeamAvatars.tsx +58 -0
  150. package/src/ui/components/icons.tsx +37 -0
  151. package/src/ui/screens/chat/ChatView.styles.ts +70 -0
  152. package/src/ui/screens/chat/ChatView.tsx +345 -35
  153. package/src/ui/screens/chat/ChatView.types.ts +51 -2
@@ -24,6 +24,18 @@ const ar = {
24
24
  emptyConversation: 'أرسل رسالة لبدء المحادثة',
25
25
  messagePlaceholder: 'اكتب رسالة...',
26
26
  attachFile: 'إرفاق ملف',
27
+ attachPhotoLibrary: 'مكتبة الصور',
28
+ attachTakePhoto: 'التقاط صورة',
29
+ attachChooseFile: 'ملف',
30
+ removeAttachment: 'إزالة {name}',
31
+ attachmentTooLarge: 'الملف كبير جدًا (الحد الأقصى {max})',
32
+ attachmentTooMany: 'يمكنك إرفاق {count} ملفات كحد أقصى',
33
+ attachmentsTooLargeTogether: 'المرفقات كبيرة جدًا لإرسالها معًا — أرسل بعضها في رسالة أخرى',
34
+ attachmentFailed: 'تعذر إرفاق هذا الملف',
35
+ imageLoadFailed: 'تعذر تحميل هذه الصورة',
36
+ openImageExternally: 'فتح الصورة',
37
+ cameraPermissionDenied: 'اسمح بالوصول إلى الكاميرا من الإعدادات لالتقاط صورة',
38
+ cancel: 'إلغاء',
27
39
  failedToSend: 'تعذر الإرسال',
28
40
  thinking: 'يكتب',
29
41
  messages: 'الرسائل',
@@ -60,6 +72,11 @@ const ar = {
60
72
  today: 'اليوم',
61
73
  yesterday: 'أمس',
62
74
  conversationUpdated: 'تم تحديث المحادثة',
75
+ messageDeleted: 'تم حذف هذه الرسالة',
76
+ messageSent: 'تم الإرسال',
77
+ messageSeen: 'تمت المشاهدة',
78
+ waitingForTeammate: 'بانتظار أحد أعضاء الفريق',
79
+ joinedConversation: 'انضم إلى المحادثة',
63
80
  procedureSend: 'إرسال التفاصيل',
64
81
  procedureSent: 'تم الإرسال',
65
82
  fieldRequired: '{field} مطلوب',
@@ -68,6 +85,10 @@ const ar = {
68
85
  outboundTitle: 'تحديث جديد',
69
86
  outboundCta: 'اعرف المزيد',
70
87
  dismiss: 'تجاهل',
88
+ notificationReplyFrom: 'رد من {name}',
89
+ notificationNewReply: 'رد جديد',
90
+ notificationAttachment: 'أرسل مرفقًا',
91
+ notificationOpenHint: 'يفتح المحادثة',
71
92
  blockService: 'خدمة',
72
93
  blockProduct: 'منتج',
73
94
  blockChooseTime: 'اختر وقتًا',
@@ -1 +1 @@
1
- {"version":3,"names":["ar","back","loading","loadEarlier","emptyConversation","messagePlaceholder","attachFile","failedToSend","thinking","messages","noMessages","historyHidden","startBelow","preChatTitle","preChatSubtitle","preChatSkip","preChatSubmit","viewPreviousConversations","homeRecentTitle","homeViewAllCount","homeNoConversations","homeStatusOnline","homeStatusAway","unreadBadge","team","home","close","retry","connectionError","connecting","chatUnavailable","identityVerificationError","widgetCrashed","timeJustNow","timeMinutes","timeHours","timeDays","timeMonths","timeYears","today","yesterday","conversationUpdated","procedureSend","procedureSent","fieldRequired","invalidEmail","working","outboundTitle","outboundCta","dismiss","blockService","blockProduct","blockChooseTime","blockProfessional","blockPriceOffer","BUNDLED_TRANSLATIONS","exports","baseLanguage","locale","split","toLowerCase"],"sourceRoot":"../../src","sources":["locales.ts"],"mappings":";;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAMA,MAAMA,EAAY,GAAG;EACnBC,IAAI,EAAE,MAAM;EACZC,OAAO,EAAE,iBAAiB;EAC1BC,WAAW,EAAE,uBAAuB;EACpCC,iBAAiB,EAAE,0BAA0B;EAC7CC,kBAAkB,EAAE,eAAe;EACnCC,UAAU,EAAE,WAAW;EACvBC,YAAY,EAAE,cAAc;EAC5BC,QAAQ,EAAE,MAAM;EAChBC,QAAQ,EAAE,SAAS;EACnBC,UAAU,EAAE,mBAAmB;EAC/BC,aAAa,EAAE,oBAAoB;EACnCC,UAAU,EAAE,uBAAuB;EACnCC,YAAY,EAAE,aAAa;EAC3BC,eAAe,EAAE,mDAAmD;EACpEC,WAAW,EAAE,MAAM;EACnBC,aAAa,EAAE,eAAe;EAC9BC,yBAAyB,EAAE,uBAAuB;EAClDC,eAAe,EAAE,QAAQ;EACzBC,gBAAgB,EAAE,oBAAoB;EACtCC,mBAAmB,EAAE,oBAAoB;EACzCC,gBAAgB,EAAE,YAAY;EAC9BC,cAAc,EAAE,gBAAgB;EAChCC,WAAW,EAAE,oBAAoB;EACjCC,IAAI,EAAE,QAAQ;EACdC,IAAI,EAAE,UAAU;EAChBC,KAAK,EAAE,OAAO;EACdC,KAAK,EAAE,gBAAgB;EACvBC,eAAe,EAAE,8CAA8C;EAC/DC,UAAU,EAAE,qBAAqB;EACjCC,eAAe,EAAE,4BAA4B;EAC7CC,yBAAyB,EAAE,mDAAmD;EAC9EC,aAAa,EAAE,aAAa;EAC5B;EACAC,WAAW,EAAE,MAAM;EACnBC,WAAW,EAAE,WAAW;EACxBC,SAAS,EAAE,WAAW;EACtBC,QAAQ,EAAE,WAAW;EACrBC,UAAU,EAAE,aAAa;EACzBC,SAAS,EAAE,aAAa;EACxBC,KAAK,EAAE,OAAO;EACdC,SAAS,EAAE,KAAK;EAChBC,mBAAmB,EAAE,mBAAmB;EACxCC,aAAa,EAAE,gBAAgB;EAC/BC,aAAa,EAAE,YAAY;EAC3BC,aAAa,EAAE,eAAe;EAC9BC,YAAY,EAAE,+BAA+B;EAC7CC,OAAO,EAAE,eAAe;EACxBC,aAAa,EAAE,YAAY;EAC3BC,WAAW,EAAE,aAAa;EAC1BC,OAAO,EAAE,OAAO;EAChBC,YAAY,EAAE,MAAM;EACpBC,YAAY,EAAE,MAAM;EACpBC,eAAe,EAAE,YAAY;EAC7BC,iBAAiB,EAAE,QAAQ;EAC3BC,eAAe,EAAE;AACnB,CAAC;AAEM,MAAMC,oBAA8C,GAAAC,OAAA,CAAAD,oBAAA,GAAG;EAAEvD;AAAG,CAAC;;AAEpE;AACO,SAASyD,YAAYA,CAACC,MAAsB,EAAU;EAC3D,OAAO,CAACA,MAAM,IAAI,EAAE,EAAEC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAEC,WAAW,CAAC,CAAC,IAAI,EAAE;AAC7D","ignoreList":[]}
1
+ {"version":3,"names":["ar","back","loading","loadEarlier","emptyConversation","messagePlaceholder","attachFile","attachPhotoLibrary","attachTakePhoto","attachChooseFile","removeAttachment","attachmentTooLarge","attachmentTooMany","attachmentsTooLargeTogether","attachmentFailed","imageLoadFailed","openImageExternally","cameraPermissionDenied","cancel","failedToSend","thinking","messages","noMessages","historyHidden","startBelow","preChatTitle","preChatSubtitle","preChatSkip","preChatSubmit","viewPreviousConversations","homeRecentTitle","homeViewAllCount","homeNoConversations","homeStatusOnline","homeStatusAway","unreadBadge","team","home","close","retry","connectionError","connecting","chatUnavailable","identityVerificationError","widgetCrashed","timeJustNow","timeMinutes","timeHours","timeDays","timeMonths","timeYears","today","yesterday","conversationUpdated","messageDeleted","messageSent","messageSeen","waitingForTeammate","joinedConversation","procedureSend","procedureSent","fieldRequired","invalidEmail","working","outboundTitle","outboundCta","dismiss","notificationReplyFrom","notificationNewReply","notificationAttachment","notificationOpenHint","blockService","blockProduct","blockChooseTime","blockProfessional","blockPriceOffer","BUNDLED_TRANSLATIONS","exports","baseLanguage","locale","split","toLowerCase"],"sourceRoot":"../../src","sources":["locales.ts"],"mappings":"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","ignoreList":[]}
@@ -11,6 +11,7 @@ var _deviceId = require("../device-id.js");
11
11
  var _events = require("../events.js");
12
12
  var _pushNotifications = require("../push/push-notifications.js");
13
13
  var _storage = require("../storage.js");
14
+ var _pickers = require("../attachments/pickers.js");
14
15
  var _types = require("../types.js");
15
16
  var _safeUrl = require("../ui/utils/safe-url.js");
16
17
  /**
@@ -23,7 +24,7 @@ var _safeUrl = require("../ui/utils/safe-url.js");
23
24
  * only a subscriber.
24
25
  */
25
26
 
26
- const SDK_VERSION = '@repzo/widget-react-native@1.0.0';
27
+ const SDK_VERSION = '@repzo/widget-react-native@1.0.4';
27
28
 
28
29
  /** The platform this session reports — mobile sessions get the Mobile SDKs overrides. */
29
30
  function sessionPlatform() {
@@ -71,7 +72,8 @@ const INITIAL_STATE = {
71
72
  locale: 'en',
72
73
  prefillText: '',
73
74
  outboundMessage: null,
74
- visitorProfile: {}
75
+ visitorProfile: {},
76
+ inAppNotification: null
75
77
  };
76
78
 
77
79
  /** Everything in state that belongs to the signed-in visitor. */
@@ -90,7 +92,8 @@ const USER_SCOPED_STATE = {
90
92
  unreadByConversation: {},
91
93
  prefillText: '',
92
94
  outboundMessage: null,
93
- visitorProfile: {}
95
+ visitorProfile: {},
96
+ inAppNotification: null
94
97
  };
95
98
  class WidgetStore {
96
99
  client = new _client.WidgetApiClient();
@@ -104,6 +107,12 @@ class WidgetStore {
104
107
  typingTimer = null;
105
108
  pendingAgentByConversation = {};
106
109
  bootConfig = null;
110
+
111
+ /** `boot({ inAppNotifications })` — the card over the app for new replies. */
112
+ inAppNotificationsEnabled = true;
113
+
114
+ /** The launch card (see showUnreadOnLaunch) is offered once per visitor session. */
115
+ launchCardOffered = false;
107
116
  bootPromise = null;
108
117
 
109
118
  /** Identity key of the in-flight boot — a boot for someone else is not deduped. */
@@ -120,6 +129,8 @@ class WidgetStore {
120
129
  lastTypingPingAt = 0;
121
130
  visitorTypingActive = false;
122
131
  seenMessageIds = [];
132
+ /** Statuses (e.g. "read") that arrived for an id before a send response revealed it. */
133
+ earlyStatuses = new Map();
123
134
 
124
135
  /**
125
136
  * Identity generation. Bumped whenever boot/login/logout is requested; every
@@ -188,6 +199,9 @@ class WidgetStore {
188
199
  };
189
200
  };
190
201
  getState = () => this.state;
202
+
203
+ /** Composer identity: explicit opens reset it; a draft receiving its server ID does not. */
204
+ getThreadGeneration = () => this.threadGeneration;
191
205
  setState(patch) {
192
206
  const previous = this.state;
193
207
  const resolved = typeof patch === 'function' ? patch(previous) : patch;
@@ -198,6 +212,13 @@ class WidgetStore {
198
212
  // The total is always derived from the per-thread map, so no surface can
199
213
  // zero the badge while threads stay unread.
200
214
  next.unreadCount = sumUnread(next.unreadByConversation);
215
+ // The in-app card only lives while the messenger is closed and its thread
216
+ // is unread — opening the widget, reading the thread (here or on another
217
+ // device) or logging out all take it down without each path clearing it.
218
+ const card = next.inAppNotification;
219
+ if (card && (next.isOpen || !next.unreadByConversation[card.conversationId])) {
220
+ next.inAppNotification = null;
221
+ }
201
222
  this.state = next;
202
223
  if (next.unreadCount !== previous.unreadCount) {
203
224
  this.events.emit(_events.RepzoWidgetEvents.UnreadCountDidChange, {
@@ -241,6 +262,10 @@ class WidgetStore {
241
262
  }
242
263
  const baseUrl = assertSecureBaseUrl(options.baseUrl?.trim() || _types.DEFAULT_BASE_URL);
243
264
  if (options.onOpenUrl !== undefined) (0, _safeUrl.setOpenUrlHandler)(options.onOpenUrl ?? null);
265
+ if (options.attachments !== undefined) (0, _pickers.setAttachmentOptions)(options.attachments ?? null);
266
+ if (options.inAppNotifications !== undefined) {
267
+ this.inAppNotificationsEnabled = options.inAppNotifications !== false;
268
+ }
244
269
  const sameTarget = this.bootConfig?.baseUrl === baseUrl && this.bootConfig?.channelAccountId === options.channelAccountId;
245
270
  const userKey = options.user ? identityKey(options.user) : null;
246
271
  if (sameTarget && this.bootPromise && (!userKey || userKey === this.bootingUserKey)) {
@@ -445,8 +470,12 @@ class WidgetStore {
445
470
  if (this.pendingConversationId) {
446
471
  const conversationId = this.pendingConversationId;
447
472
  this.pendingConversationId = null;
473
+ // Launched into a thread (push tap): that is this session's launch, so
474
+ // a later silent re-init must not offer the card either.
475
+ this.launchCardOffered = true;
448
476
  void this.openConversation(conversationId);
449
477
  } else {
478
+ this.showUnreadOnLaunch();
450
479
  // A re-init after a 401 means the stream was down: catch the open
451
480
  // thread up (a no-op when nothing is on screen).
452
481
  void this.refreshOpenThread();
@@ -660,6 +689,7 @@ class WidgetStore {
660
689
  this.seenMessageIds = [];
661
690
  this.visitorTypingActive = false;
662
691
  this.lastTypingPingAt = 0;
692
+ this.launchCardOffered = false;
663
693
  this.setState({
664
694
  ...USER_SCOPED_STATE
665
695
  });
@@ -798,7 +828,7 @@ class WidgetStore {
798
828
  }
799
829
  }
800
830
  handleRealtimeEvent(event, data) {
801
- if ((event === 'message.new' || event === 'conversation.event') && this.shouldHoldForDraft(data?.conversationId)) {
831
+ if ((event === 'message.new' || event === 'message.deleted' || event === 'message.status' || event === 'conversation.event') && this.shouldHoldForDraft(data?.conversationId)) {
802
832
  this.draftEvents.push({
803
833
  event,
804
834
  data
@@ -822,13 +852,20 @@ class WidgetStore {
822
852
  case 'message.new':
823
853
  this.handleNewMessage(data);
824
854
  break;
855
+ case 'message.deleted':
856
+ this.handleDeletedMessage(data);
857
+ break;
858
+ case 'message.status':
859
+ this.handleMessageStatus(data);
860
+ break;
825
861
  case 'conversation.updated':
826
862
  this.rememberConversationAgent(data);
827
863
  this.setState(current => ({
828
864
  conversations: current.conversations.map(conversation => conversation.id === data?.conversationId ? {
829
865
  ...conversation,
830
866
  agentName: data.agentName === undefined ? conversation.agentName : data.agentName,
831
- agentAvatar: data.agentAvatar === undefined ? conversation.agentAvatar : this.client.resolveUrl(data.agentAvatar)
867
+ agentAvatar: data.agentAvatar === undefined ? conversation.agentAvatar : this.client.resolveUrl(data.agentAvatar),
868
+ agentOnline: data.agentOnline === undefined ? conversation.agentOnline : data.agentOnline
832
869
  } : conversation)
833
870
  }));
834
871
  break;
@@ -926,6 +963,50 @@ class WidgetStore {
926
963
  if (this.seenMessageIds.length > SEEN_MESSAGE_LIMIT) this.seenMessageIds.shift();
927
964
  return false;
928
965
  }
966
+
967
+ /**
968
+ * A teammate deleted a message: the visitor sees "This message was deleted"
969
+ * in its place (they can't delete anything themselves), and the list is
970
+ * refreshed so its preview stops showing the text. The id stays in
971
+ * `seenMessageIds`, so a replayed `message.new` can't restore the content.
972
+ */
973
+ /**
974
+ * A teammate opened the conversation: the visitor's messages are now Seen.
975
+ * The ids are also remembered, because the event can arrive before the send
976
+ * response swaps a pending bubble's temporary id for the server id.
977
+ */
978
+ handleMessageStatus(data) {
979
+ const ids = Array.isArray(data?.messageIds) ? data.messageIds : [];
980
+ const status = typeof data?.status === 'string' ? data.status : undefined;
981
+ if (!status || ids.length === 0) return;
982
+ for (const id of ids) this.earlyStatuses.set(id, status);
983
+ if (this.earlyStatuses.size > SEEN_MESSAGE_LIMIT) {
984
+ this.earlyStatuses.delete(this.earlyStatuses.keys().next().value);
985
+ }
986
+ if (!this.isThreadOnScreen(data?.conversationId)) return;
987
+ this.setState(current => ({
988
+ messages: current.messages.map(message => ids.includes(message.id) ? {
989
+ ...message,
990
+ status
991
+ } : message)
992
+ }));
993
+ }
994
+ handleDeletedMessage(data) {
995
+ const messageId = data?.messageId;
996
+ if (!messageId) return;
997
+ if (!this.seenMessageIds.includes(messageId)) this.isReplayedMessage(messageId);
998
+ if (this.isThreadOnScreen(data?.conversationId)) {
999
+ this.setState(current => ({
1000
+ messages: current.messages.map(message => message.id === messageId ? asDeletedPlaceholder(message, new Date().toISOString()) : message)
1001
+ }));
1002
+ }
1003
+ if (this.state.inAppNotification?.messageId === messageId) {
1004
+ this.setState({
1005
+ inAppNotification: null
1006
+ });
1007
+ }
1008
+ void this.refreshConversations();
1009
+ }
929
1010
  handleNewMessage(data) {
930
1011
  if (this.isReplayedMessage(data?.messageId)) return;
931
1012
 
@@ -941,7 +1022,7 @@ class WidgetStore {
941
1022
  body: data?.body || null,
942
1023
  bodyPlain: data?.bodyPlain || null,
943
1024
  attachments: this.hydrateAttachments(data?.attachments, messageId),
944
- metadata: data?.metadata || null,
1025
+ metadata: this.hydrateMetadata(data?.metadata || null),
945
1026
  status: 'delivered',
946
1027
  createdAt: data?.createdAt || new Date().toISOString()
947
1028
  };
@@ -966,7 +1047,7 @@ class WidgetStore {
966
1047
  const alreadyPresent = current.messages.some(existing => existing.id === message.id);
967
1048
  return {
968
1049
  conversations,
969
- messages: alreadyPresent ? current.messages : [...current.messages, message],
1050
+ messages: alreadyPresent ? adoptServerAttachments(current.messages, [message]) : [...current.messages, message],
970
1051
  agentTyping: clearsTyping ? false : current.agentTyping
971
1052
  };
972
1053
  }
@@ -979,9 +1060,25 @@ class WidgetStore {
979
1060
  };
980
1061
  this.persistUnread(unreadByConversation);
981
1062
  countedAsUnread = true;
1063
+ if (!this.inAppNotificationsEnabled || current.isOpen) {
1064
+ return {
1065
+ conversations,
1066
+ unreadByConversation
1067
+ };
1068
+ }
1069
+ // Newest reply wins: one card, not a stack, like the launcher badge.
1070
+ const conversation = conversations.find(item => item.id === conversationId);
982
1071
  return {
983
1072
  conversations,
984
- unreadByConversation
1073
+ unreadByConversation,
1074
+ inAppNotification: {
1075
+ conversationId,
1076
+ messageId,
1077
+ senderName: message.senderName || conversation?.agentName || null,
1078
+ senderAvatar: conversation?.agentAvatar ?? null,
1079
+ preview: (message.bodyPlain ?? '').trim(),
1080
+ hasAttachments: (message.attachments?.length ?? 0) > 0
1081
+ }
985
1082
  };
986
1083
  });
987
1084
 
@@ -1219,6 +1316,44 @@ class WidgetStore {
1219
1316
  prefillText: prefill
1220
1317
  });
1221
1318
  }
1319
+
1320
+ /**
1321
+ * Replies that arrived while the app was closed get the same card a live
1322
+ * reply would, once per launch — so a visitor without push (not set up on
1323
+ * the channel, or permission denied) still sees them. Only the newest unread
1324
+ * thread; silent re-inits and foreground returns never re-offer it.
1325
+ */
1326
+ showUnreadOnLaunch() {
1327
+ if (this.launchCardOffered || !this.inAppNotificationsEnabled) return;
1328
+ this.launchCardOffered = true;
1329
+ const {
1330
+ isOpen,
1331
+ inAppNotification,
1332
+ conversations,
1333
+ unreadByConversation
1334
+ } = this.state;
1335
+ if (isOpen || inAppNotification) return;
1336
+ const time = conversation => Date.parse(conversation.lastMessageAt ?? conversation.createdAt) || 0;
1337
+ const newest = conversations.filter(conversation => (unreadByConversation[conversation.id] ?? 0) > 0).sort((a, b) => time(b) - time(a))[0];
1338
+ if (!newest) return;
1339
+ this.setState({
1340
+ inAppNotification: {
1341
+ conversationId: newest.id,
1342
+ messageId: `launch-${newest.id}`,
1343
+ senderName: newest.agentName,
1344
+ senderAvatar: newest.agentAvatar,
1345
+ preview: (newest.snippet ?? '').trim(),
1346
+ hasAttachments: false
1347
+ }
1348
+ });
1349
+ }
1350
+
1351
+ /** The visitor swiped the in-app card away; the thread stays unread. */
1352
+ dismissInAppNotification() {
1353
+ if (this.state.inAppNotification) this.setState({
1354
+ inAppNotification: null
1355
+ });
1356
+ }
1222
1357
  dismissOutboundMessage() {
1223
1358
  const outbound = this.state.outboundMessage;
1224
1359
  if (outbound?.id) this.track('widget_outbound_dismissed', {
@@ -1298,9 +1433,10 @@ class WidgetStore {
1298
1433
  // Live replies and optimistic sends may have arrived since this page
1299
1434
  // was requested. Keep them, preferring the live copy for shared ids.
1300
1435
  const liveIds = new Set(current.messages.map(message => message.id));
1301
- const history = this.hydrateMessages(result.data).filter(message => !liveIds.has(message.id));
1436
+ const page = this.hydrateMessages(result.data);
1437
+ const history = page.filter(message => !liveIds.has(message.id));
1302
1438
  return {
1303
- messages: sortByCreatedAt([...history, ...current.messages]),
1439
+ messages: sortByCreatedAt([...history, ...adoptServerAttachments(current.messages, page)]),
1304
1440
  messagesLoading: false,
1305
1441
  hasMoreMessages: result.meta.hasMore,
1306
1442
  messageCursor: result.meta.nextCursor
@@ -1370,7 +1506,10 @@ class WidgetStore {
1370
1506
  this.setState(current => {
1371
1507
  const known = new Set(current.messages.map(message => message.id));
1372
1508
  const missing = fresh.filter(message => !known.has(message.id));
1373
- if (missing.length === 0) return {};
1509
+ const upgraded = adoptServerStatuses(adoptServerDeletions(adoptServerAttachments(current.messages, fresh), fresh), fresh);
1510
+ if (missing.length === 0) return upgraded === current.messages ? {} : {
1511
+ messages: upgraded
1512
+ };
1374
1513
  const local = current.messages.filter(isLocalMessage);
1375
1514
  const hasServerMessages = local.length < current.messages.length;
1376
1515
  // No overlap means the gap is longer than a page: restart from the
@@ -1383,7 +1522,7 @@ class WidgetStore {
1383
1522
  };
1384
1523
  }
1385
1524
  return {
1386
- messages: sortByCreatedAt([...current.messages, ...missing])
1525
+ messages: sortByCreatedAt([...upgraded, ...missing])
1387
1526
  };
1388
1527
  });
1389
1528
  // The server just moved the read cursor — mirror it locally.
@@ -1401,9 +1540,26 @@ class WidgetStore {
1401
1540
  hydrateMessages(page) {
1402
1541
  return page.map(message => ({
1403
1542
  ...message,
1404
- attachments: this.hydrateAttachments(message.attachments, message.id)
1543
+ attachments: this.hydrateAttachments(message.attachments, message.id),
1544
+ metadata: this.hydrateMetadata(message.metadata)
1405
1545
  })).reverse();
1406
1546
  }
1547
+
1548
+ /** The "joined" line's avatar can be a server-relative media path. */
1549
+ hydrateMetadata(metadata) {
1550
+ if (!metadata || typeof metadata.agentAvatar !== 'string') return metadata ?? null;
1551
+ return {
1552
+ ...metadata,
1553
+ agentAvatar: this.client.resolveUrl(metadata.agentAvatar)
1554
+ };
1555
+ }
1556
+
1557
+ /**
1558
+ * Rejects when the message wasn't sent, so the composer can keep
1559
+ * attachments for a retry. A text-only bubble is marked failed; one with
1560
+ * attachments is removed instead — the composer's chips are the retry, and
1561
+ * keeping both would leave a duplicate after a successful resend.
1562
+ */
1407
1563
  async sendMessage(body, attachments = [], agentUiAction) {
1408
1564
  const trimmed = body.trim();
1409
1565
  if (!trimmed && attachments.length === 0) return;
@@ -1420,7 +1576,16 @@ class WidgetStore {
1420
1576
  senderName: visitorProfile.name || 'You',
1421
1577
  body: trimmed ? `<p>${trimmed}</p>` : '',
1422
1578
  bodyPlain: trimmed,
1423
- attachments: attachments.length > 0 ? attachments : null,
1579
+ // The local preview, never a data URL: the bubble shows up at once and
1580
+ // state never holds megabytes of base64. Without a local file the
1581
+ // bubble shows the name until the server copy replaces it.
1582
+ attachments: attachments.length > 0 ? attachments.map((attachment, index) => ({
1583
+ id: `${tempId}-${index}`,
1584
+ name: attachment.name,
1585
+ url: attachment.previewUrl && !/^data:/i.test(attachment.previewUrl) ? attachment.previewUrl : '',
1586
+ contentType: attachment.contentType,
1587
+ size: attachment.size
1588
+ })) : null,
1424
1589
  metadata: null,
1425
1590
  status: 'pending',
1426
1591
  createdAt: new Date().toISOString()
@@ -1434,7 +1599,7 @@ class WidgetStore {
1434
1599
  attachmentCount: attachments.length
1435
1600
  });
1436
1601
  const markFailed = () => this.setState(current => ({
1437
- messages: current.messages.map(message => message.id === tempId ? {
1602
+ messages: attachments.length > 0 ? current.messages.filter(message => message.id !== tempId) : current.messages.map(message => message.id === tempId ? {
1438
1603
  ...message,
1439
1604
  status: 'failed'
1440
1605
  } : message)
@@ -1459,7 +1624,7 @@ class WidgetStore {
1459
1624
  // don't open a thread nobody is looking at.
1460
1625
  if (!conversationId && this.threadGeneration !== generation) {
1461
1626
  markFailed();
1462
- return;
1627
+ throw new Error('The conversation this message was queued for was never created');
1463
1628
  }
1464
1629
  }
1465
1630
  let createdId = null;
@@ -1468,7 +1633,17 @@ class WidgetStore {
1468
1633
  conversationId: conversationId || undefined,
1469
1634
  forceNewConversation: !conversationId,
1470
1635
  body: trimmed,
1471
- attachments: attachments.length > 0 ? attachments : undefined,
1636
+ attachments: attachments.length > 0 ? attachments.map(({
1637
+ name,
1638
+ url,
1639
+ contentType,
1640
+ size
1641
+ }) => ({
1642
+ name,
1643
+ url,
1644
+ contentType,
1645
+ size
1646
+ })) : undefined,
1472
1647
  visitorName: visitorProfile.name,
1473
1648
  visitorEmail: visitorProfile.email,
1474
1649
  agentUiAction
@@ -1482,7 +1657,7 @@ class WidgetStore {
1482
1657
  const messages = delivered ? current.messages.filter(message => message.id !== tempId) : current.messages.map(message => message.id === tempId ? {
1483
1658
  ...message,
1484
1659
  id: result.messageId,
1485
- status: 'sent'
1660
+ status: this.earlyStatuses.get(result.messageId) ?? 'sent'
1486
1661
  } : message);
1487
1662
  if (!createdId) return {
1488
1663
  messages
@@ -1617,6 +1792,69 @@ function isLocalMessage(message) {
1617
1792
  return message.id.startsWith('temp-');
1618
1793
  }
1619
1794
 
1795
+ /**
1796
+ * A sent visitor message keeps its local previews (a `file://` URI, or no URL
1797
+ * at all) until the server copy shows up — the stream echo or a history page.
1798
+ * Its attachments, the only ones that can be opened, then replace them.
1799
+ */
1800
+ /** A "Seen" missed while the stream was down shows up on the next re-read. */
1801
+ function adoptServerStatuses(messages, server) {
1802
+ const seen = new Set(server.filter(message => message.status === 'read').map(message => message.id));
1803
+ if (seen.size === 0) return messages;
1804
+ let changed = false;
1805
+ const next = messages.map(message => {
1806
+ if (!seen.has(message.id) || message.status === 'read') return message;
1807
+ changed = true;
1808
+ return {
1809
+ ...message,
1810
+ status: 'read'
1811
+ };
1812
+ });
1813
+ return changed ? next : messages;
1814
+ }
1815
+
1816
+ /** Keeps who/when, drops everything the visitor could read. */
1817
+ function asDeletedPlaceholder(message, deletedAt) {
1818
+ return {
1819
+ ...message,
1820
+ body: null,
1821
+ bodyPlain: null,
1822
+ attachments: null,
1823
+ metadata: null,
1824
+ deletedAt
1825
+ };
1826
+ }
1827
+
1828
+ /** A deletion missed while the stream was down shows up on the next re-read. */
1829
+ function adoptServerDeletions(messages, server) {
1830
+ const deleted = new Map(server.filter(message => message.deletedAt).map(message => [message.id, message.deletedAt]));
1831
+ if (deleted.size === 0) return messages;
1832
+ let changed = false;
1833
+ const next = messages.map(message => {
1834
+ const deletedAt = deleted.get(message.id);
1835
+ if (!deletedAt || message.deletedAt) return message;
1836
+ changed = true;
1837
+ return asDeletedPlaceholder(message, deletedAt);
1838
+ });
1839
+ return changed ? next : messages;
1840
+ }
1841
+ function adoptServerAttachments(messages, server) {
1842
+ const serverCopies = new Map(server.filter(message => message.attachments?.length).map(message => [message.id, message]));
1843
+ if (serverCopies.size === 0) return messages;
1844
+ let changed = false;
1845
+ const next = messages.map(message => {
1846
+ const copy = serverCopies.get(message.id);
1847
+ const hasLocal = message.attachments?.some(attachment => !/^https?:\/\//i.test(attachment.url));
1848
+ if (!copy || !hasLocal) return message;
1849
+ changed = true;
1850
+ return {
1851
+ ...message,
1852
+ attachments: copy.attachments
1853
+ };
1854
+ });
1855
+ return changed ? next : messages;
1856
+ }
1857
+
1620
1858
  /** Stable, so same-instant rows keep their order; bad dates sort as oldest. */
1621
1859
  function sortByCreatedAt(messages) {
1622
1860
  const time = message => Date.parse(message.createdAt) || 0;