@weavy/uikit-react 12.1.0 → 14.0.0

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 (280) hide show
  1. package/changelog.md +60 -0
  2. package/dist/cjs/index.js +28 -6
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/types/client/WeavyClient.d.ts +8 -1
  5. package/dist/cjs/types/components/Attachment.d.ts +2 -1
  6. package/dist/cjs/types/components/Chat.d.ts +1 -1
  7. package/dist/cjs/types/components/Messages.d.ts +3 -1
  8. package/dist/cjs/types/components/PdfViewer.d.ts +3 -1
  9. package/dist/cjs/types/components/Preview.d.ts +8 -10
  10. package/dist/cjs/types/contexts/PreviewContext.d.ts +2 -1
  11. package/dist/cjs/types/contexts/WeavyContext.d.ts +2 -3
  12. package/dist/cjs/types/hooks/useConversations.d.ts +1 -1
  13. package/dist/cjs/types/hooks/useMutateMessage.d.ts +1 -1
  14. package/dist/cjs/types/hooks/useMutateRead.d.ts +1 -0
  15. package/dist/cjs/types/types/Chat.d.ts +2 -1
  16. package/dist/cjs/types/types/Message.d.ts +2 -0
  17. package/dist/cjs/types/types/types.d.ts +63 -9
  18. package/dist/cjs/types/ui/Spinner.d.ts +10 -0
  19. package/dist/cjs/types/utils/fileUtilities.d.ts +1 -4
  20. package/dist/css/weavy-chat.css +1803 -1041
  21. package/dist/css/weavy-messenger.css +2141 -1360
  22. package/dist/css/weavy.css +1943 -1162
  23. package/dist/esm/index.js +28 -6
  24. package/dist/esm/index.js.map +1 -1
  25. package/dist/esm/types/client/WeavyClient.d.ts +8 -1
  26. package/dist/esm/types/components/Attachment.d.ts +2 -1
  27. package/dist/esm/types/components/Chat.d.ts +1 -1
  28. package/dist/esm/types/components/Messages.d.ts +3 -1
  29. package/dist/esm/types/components/PdfViewer.d.ts +3 -1
  30. package/dist/esm/types/components/Preview.d.ts +8 -10
  31. package/dist/esm/types/contexts/PreviewContext.d.ts +2 -1
  32. package/dist/esm/types/contexts/WeavyContext.d.ts +2 -3
  33. package/dist/esm/types/hooks/useConversations.d.ts +1 -1
  34. package/dist/esm/types/hooks/useMutateMessage.d.ts +1 -1
  35. package/dist/esm/types/hooks/useMutateRead.d.ts +1 -0
  36. package/dist/esm/types/types/Chat.d.ts +2 -1
  37. package/dist/esm/types/types/Message.d.ts +2 -0
  38. package/dist/esm/types/types/types.d.ts +63 -9
  39. package/dist/esm/types/ui/Spinner.d.ts +10 -0
  40. package/dist/esm/types/utils/fileUtilities.d.ts +1 -4
  41. package/dist/index.d.ts +15 -7
  42. package/package.json +2 -2
  43. package/rollup.config.js +3 -1
  44. package/src/client/WeavyClient.ts +105 -29
  45. package/src/components/Attachment.tsx +8 -7
  46. package/src/components/Chat.tsx +8 -7
  47. package/src/components/Conversation.tsx +29 -23
  48. package/src/components/ConversationBadge.tsx +7 -5
  49. package/src/components/ConversationForm.tsx +1 -1
  50. package/src/components/ConversationList.tsx +59 -11
  51. package/src/components/ConversationListItem.tsx +71 -54
  52. package/src/components/FileBrowser.tsx +53 -50
  53. package/src/components/MeetingCard.tsx +35 -13
  54. package/src/components/Meetings.tsx +1 -1
  55. package/src/components/Message.tsx +41 -41
  56. package/src/components/Messages.tsx +62 -61
  57. package/src/components/Messenger.tsx +7 -2
  58. package/src/components/NewConversation.tsx +1 -1
  59. package/src/components/PdfViewer.tsx +93 -88
  60. package/src/components/Preview.tsx +115 -54
  61. package/src/components/Reactions.tsx +11 -5
  62. package/src/components/SearchUsers.tsx +21 -11
  63. package/src/components/SeenBy.tsx +13 -7
  64. package/src/components/Typing.tsx +11 -12
  65. package/src/contexts/PreviewContext.tsx +90 -16
  66. package/src/contexts/UserContext.tsx +1 -1
  67. package/src/contexts/WeavyContext.tsx +10 -7
  68. package/src/hooks/useBadge.ts +2 -6
  69. package/src/hooks/useChat.ts +3 -14
  70. package/src/hooks/useConversation.ts +1 -7
  71. package/src/hooks/useConversations.ts +15 -11
  72. package/src/hooks/useFileUploader.ts +6 -8
  73. package/src/hooks/useMembers.ts +1 -7
  74. package/src/hooks/useMessages.ts +1 -7
  75. package/src/hooks/useMutateChat.ts +6 -11
  76. package/src/hooks/useMutateConversation.ts +7 -10
  77. package/src/hooks/useMutateConversationName.ts +10 -12
  78. package/src/hooks/useMutateDeleteReaction.ts +3 -8
  79. package/src/hooks/useMutateExternalBlobs.ts +6 -11
  80. package/src/hooks/useMutateMeeting.ts +6 -11
  81. package/src/hooks/useMutateMembers.ts +8 -13
  82. package/src/hooks/useMutateMessage.ts +9 -18
  83. package/src/hooks/useMutatePinned.ts +3 -8
  84. package/src/hooks/useMutateReaction.ts +6 -12
  85. package/src/hooks/useMutateRead.ts +5 -12
  86. package/src/hooks/useMutateRemoveMembers.ts +7 -12
  87. package/src/hooks/useMutateTyping.ts +6 -11
  88. package/src/hooks/usePresence.ts +2 -3
  89. package/src/hooks/useReactions.ts +11 -12
  90. package/src/hooks/useSearchUsers.ts +1 -6
  91. package/src/hooks/useUser.ts +3 -14
  92. package/src/scss/theme/_alert.scss +61 -63
  93. package/src/scss/theme/_appbar.scss +105 -28
  94. package/src/scss/theme/_avatar.scss +23 -28
  95. package/src/scss/theme/_badge.scss +26 -18
  96. package/src/scss/theme/_buttons.scss +107 -52
  97. package/src/scss/theme/_card.scss +102 -4
  98. package/src/scss/theme/_checkbox.scss +16 -20
  99. package/src/scss/theme/_code-vscode-dark.scss +184 -0
  100. package/src/scss/theme/_code-vscode-light.scss +179 -0
  101. package/src/scss/theme/_code.scss +9 -114
  102. package/src/scss/theme/_comment-editor-cm.scss +97 -0
  103. package/src/scss/theme/_comment-editor.scss +129 -0
  104. package/src/scss/theme/_comments.scss +66 -0
  105. package/src/scss/theme/_content.scss +33 -5
  106. package/src/scss/theme/_conversations.scss +19 -78
  107. package/src/scss/theme/_dropdown.scss +102 -15
  108. package/src/scss/theme/_embed.scss +135 -0
  109. package/src/scss/theme/_facepile.scss +11 -0
  110. package/src/scss/theme/_filebrowser.scss +1 -1
  111. package/src/scss/theme/_files.scss +77 -48
  112. package/src/scss/theme/_grid.scss +8 -0
  113. package/src/scss/theme/_icons.scss +155 -19
  114. package/src/scss/theme/_image-grid.scss +7 -10
  115. package/src/scss/theme/_input.scss +160 -0
  116. package/src/scss/theme/_item.scss +169 -0
  117. package/src/scss/theme/_list.scss +57 -0
  118. package/src/scss/theme/_meeting.scss +11 -0
  119. package/src/scss/theme/_message-editor-cm.scss +95 -0
  120. package/src/scss/theme/_message-editor.scss +66 -20
  121. package/src/scss/theme/_messages.scss +51 -105
  122. package/src/scss/theme/_meta.scss +12 -0
  123. package/src/scss/theme/_overlays.scss +31 -76
  124. package/src/scss/theme/_pager.scss +5 -1
  125. package/src/scss/theme/_pane.scss +13 -2
  126. package/src/scss/theme/_panels.scss +34 -25
  127. package/src/scss/theme/_picker-list.scss +5 -3
  128. package/src/scss/theme/_placeholder.scss +19 -0
  129. package/src/scss/theme/_poll.scss +49 -0
  130. package/src/scss/theme/_post-editor-cm.scss +100 -0
  131. package/src/scss/theme/_post-editor.scss +127 -0
  132. package/src/scss/theme/_post.scss +83 -0
  133. package/src/scss/theme/_preview-code.scss +14 -0
  134. package/src/scss/theme/_preview-embed.scss +11 -5
  135. package/src/scss/theme/_preview-image.scss +8 -26
  136. package/src/scss/theme/_preview-media.scss +1 -0
  137. package/src/scss/theme/_preview-pdf.scss +10 -15
  138. package/src/scss/theme/_preview-text.scss +1 -1
  139. package/src/scss/theme/_preview.scss +59 -76
  140. package/src/scss/theme/_reactions.scss +48 -17
  141. package/src/scss/theme/_sheet.scss +59 -0
  142. package/src/scss/theme/_sidebar.scss +86 -0
  143. package/src/scss/theme/_spinner.scss +11 -7
  144. package/src/scss/theme/_tab.scss +72 -0
  145. package/src/scss/theme/_tables.scss +70 -23
  146. package/src/scss/theme/_toasts.scss +56 -26
  147. package/src/scss/theme/_type.scss +41 -0
  148. package/src/scss/theme/{mixins → base}/_backdrop.scss +0 -0
  149. package/src/scss/theme/{bootstrap/mixins → base}/_breakpoints.scss +9 -0
  150. package/src/scss/theme/base/_colors.scss +315 -0
  151. package/src/scss/theme/base/_md.scss +19 -0
  152. package/src/scss/theme/base/_palette.scss +130 -0
  153. package/src/scss/theme/{mixins → base}/_position.scss +5 -5
  154. package/src/scss/theme/base/_reboot.scss +51 -0
  155. package/src/scss/theme/base/_scroll.scss +180 -0
  156. package/src/scss/theme/base/_svg.scss +49 -0
  157. package/src/scss/theme/base/_text.scss +23 -0
  158. package/src/scss/theme/base/_vars.scss +203 -0
  159. package/src/scss/theme/{fonts → base/fonts}/_fontmapping-roboto.scss +0 -0
  160. package/src/scss/theme/{fonts → base/fonts}/_fontmapping-segoe-ui.scss +0 -0
  161. package/src/scss/theme/base/fonts/_index.scss +2 -0
  162. package/src/scss/weavy-chat.scss +11 -4
  163. package/src/scss/weavy-messenger.scss +38 -21
  164. package/src/types/Chat.ts +2 -1
  165. package/src/types/Message.ts +3 -1
  166. package/src/types/types.ts +72 -10
  167. package/src/ui/Icon.tsx +1 -1
  168. package/src/ui/Spinner.tsx +19 -0
  169. package/src/utils/fileUtilities.ts +11 -125
  170. package/src/utils/infiniteScroll.js +11 -2
  171. package/src/utils/postal-parent.js +398 -0
  172. package/src/utils/promise.js +187 -0
  173. package/src/utils/scrollbarDetection.js +68 -9
  174. package/src/utils/utils.js +547 -0
  175. package/src/scss/theme/_attachments.scss +0 -74
  176. package/src/scss/theme/_cm-editor.scss +0 -42
  177. package/src/scss/theme/_colors.scss +0 -520
  178. package/src/scss/theme/_config.scss +0 -6
  179. package/src/scss/theme/_inputs.scss +0 -28
  180. package/src/scss/theme/_nav.scss +0 -52
  181. package/src/scss/theme/_palette.scss +0 -165
  182. package/src/scss/theme/_preview-icon.scss +0 -41
  183. package/src/scss/theme/_reboot.scss +0 -41
  184. package/src/scss/theme/_root.scss +0 -2
  185. package/src/scss/theme/_scroll.scss +0 -55
  186. package/src/scss/theme/_search.scss +0 -68
  187. package/src/scss/theme/_turbo.scss +0 -17
  188. package/src/scss/theme/_variables.scss +0 -139
  189. package/src/scss/theme/bootstrap/_accordion.scss +0 -146
  190. package/src/scss/theme/bootstrap/_alert.scss +0 -71
  191. package/src/scss/theme/bootstrap/_badge.scss +0 -38
  192. package/src/scss/theme/bootstrap/_breadcrumb.scss +0 -40
  193. package/src/scss/theme/bootstrap/_button-group.scss +0 -142
  194. package/src/scss/theme/bootstrap/_buttons.scss +0 -186
  195. package/src/scss/theme/bootstrap/_card.scss +0 -234
  196. package/src/scss/theme/bootstrap/_carousel.scss +0 -229
  197. package/src/scss/theme/bootstrap/_close.scss +0 -40
  198. package/src/scss/theme/bootstrap/_containers.scss +0 -41
  199. package/src/scss/theme/bootstrap/_dropdown.scss +0 -248
  200. package/src/scss/theme/bootstrap/_forms.scss +0 -9
  201. package/src/scss/theme/bootstrap/_functions.scss +0 -302
  202. package/src/scss/theme/bootstrap/_grid.scss +0 -33
  203. package/src/scss/theme/bootstrap/_helpers.scss +0 -10
  204. package/src/scss/theme/bootstrap/_images.scss +0 -42
  205. package/src/scss/theme/bootstrap/_list-group.scss +0 -191
  206. package/src/scss/theme/bootstrap/_maps.scss +0 -54
  207. package/src/scss/theme/bootstrap/_mixins.scss +0 -43
  208. package/src/scss/theme/bootstrap/_modal.scss +0 -237
  209. package/src/scss/theme/bootstrap/_nav.scss +0 -172
  210. package/src/scss/theme/bootstrap/_navbar.scss +0 -276
  211. package/src/scss/theme/bootstrap/_offcanvas.scss +0 -143
  212. package/src/scss/theme/bootstrap/_pagination.scss +0 -109
  213. package/src/scss/theme/bootstrap/_placeholders.scss +0 -51
  214. package/src/scss/theme/bootstrap/_popover.scss +0 -196
  215. package/src/scss/theme/bootstrap/_progress.scss +0 -59
  216. package/src/scss/theme/bootstrap/_reboot.scss +0 -610
  217. package/src/scss/theme/bootstrap/_root.scss +0 -73
  218. package/src/scss/theme/bootstrap/_spinners.scss +0 -85
  219. package/src/scss/theme/bootstrap/_tables.scss +0 -164
  220. package/src/scss/theme/bootstrap/_toasts.scss +0 -70
  221. package/src/scss/theme/bootstrap/_tooltip.scss +0 -120
  222. package/src/scss/theme/bootstrap/_transitions.scss +0 -27
  223. package/src/scss/theme/bootstrap/_type.scss +0 -106
  224. package/src/scss/theme/bootstrap/_utilities.scss +0 -647
  225. package/src/scss/theme/bootstrap/_variables.scss +0 -1633
  226. package/src/scss/theme/bootstrap/forms/_floating-labels.scss +0 -74
  227. package/src/scss/theme/bootstrap/forms/_form-check.scss +0 -175
  228. package/src/scss/theme/bootstrap/forms/_form-control.scss +0 -194
  229. package/src/scss/theme/bootstrap/forms/_form-range.scss +0 -91
  230. package/src/scss/theme/bootstrap/forms/_form-select.scss +0 -71
  231. package/src/scss/theme/bootstrap/forms/_form-text.scss +0 -11
  232. package/src/scss/theme/bootstrap/forms/_input-group.scss +0 -129
  233. package/src/scss/theme/bootstrap/forms/_labels.scss +0 -36
  234. package/src/scss/theme/bootstrap/forms/_validation.scss +0 -12
  235. package/src/scss/theme/bootstrap/helpers/_clearfix.scss +0 -3
  236. package/src/scss/theme/bootstrap/helpers/_color-bg.scss +0 -10
  237. package/src/scss/theme/bootstrap/helpers/_colored-links.scss +0 -12
  238. package/src/scss/theme/bootstrap/helpers/_position.scss +0 -36
  239. package/src/scss/theme/bootstrap/helpers/_ratio.scss +0 -26
  240. package/src/scss/theme/bootstrap/helpers/_stacks.scss +0 -15
  241. package/src/scss/theme/bootstrap/helpers/_stretched-link.scss +0 -15
  242. package/src/scss/theme/bootstrap/helpers/_text-truncation.scss +0 -7
  243. package/src/scss/theme/bootstrap/helpers/_visually-hidden.scss +0 -8
  244. package/src/scss/theme/bootstrap/helpers/_vr.scss +0 -8
  245. package/src/scss/theme/bootstrap/mixins/_alert.scss +0 -15
  246. package/src/scss/theme/bootstrap/mixins/_backdrop.scss +0 -14
  247. package/src/scss/theme/bootstrap/mixins/_banner.scss +0 -9
  248. package/src/scss/theme/bootstrap/mixins/_border-radius.scss +0 -78
  249. package/src/scss/theme/bootstrap/mixins/_box-shadow.scss +0 -18
  250. package/src/scss/theme/bootstrap/mixins/_buttons.scss +0 -70
  251. package/src/scss/theme/bootstrap/mixins/_caret.scss +0 -64
  252. package/src/scss/theme/bootstrap/mixins/_clearfix.scss +0 -9
  253. package/src/scss/theme/bootstrap/mixins/_color-scheme.scss +0 -7
  254. package/src/scss/theme/bootstrap/mixins/_container.scss +0 -11
  255. package/src/scss/theme/bootstrap/mixins/_deprecate.scss +0 -10
  256. package/src/scss/theme/bootstrap/mixins/_forms.scss +0 -152
  257. package/src/scss/theme/bootstrap/mixins/_gradients.scss +0 -47
  258. package/src/scss/theme/bootstrap/mixins/_grid.scss +0 -151
  259. package/src/scss/theme/bootstrap/mixins/_image.scss +0 -16
  260. package/src/scss/theme/bootstrap/mixins/_list-group.scss +0 -24
  261. package/src/scss/theme/bootstrap/mixins/_lists.scss +0 -7
  262. package/src/scss/theme/bootstrap/mixins/_pagination.scss +0 -10
  263. package/src/scss/theme/bootstrap/mixins/_reset-text.scss +0 -17
  264. package/src/scss/theme/bootstrap/mixins/_resize.scss +0 -6
  265. package/src/scss/theme/bootstrap/mixins/_table-variants.scss +0 -24
  266. package/src/scss/theme/bootstrap/mixins/_text-truncate.scss +0 -8
  267. package/src/scss/theme/bootstrap/mixins/_transition.scss +0 -26
  268. package/src/scss/theme/bootstrap/mixins/_utilities.scss +0 -97
  269. package/src/scss/theme/bootstrap/mixins/_visually-hidden.scss +0 -29
  270. package/src/scss/theme/bootstrap/utilities/_api.scss +0 -47
  271. package/src/scss/theme/bootstrap/vendor/_rfs.scss +0 -354
  272. package/src/scss/theme/bs/_badge.scss +0 -20
  273. package/src/scss/theme/bs/_buttons.scss +0 -185
  274. package/src/scss/theme/bs/_dropdown.scss +0 -86
  275. package/src/scss/theme/bs/_forms.scss +0 -161
  276. package/src/scss/theme/bs/_list-group.scss +0 -73
  277. package/src/scss/theme/bs/_tables.scss +0 -46
  278. package/src/scss/theme/fonts/_index.scss +0 -2
  279. package/src/scss/theme/mixins/_palette.scss +0 -165
  280. package/src/scss/theme/mixins/_scrollbar.scss +0 -110
@@ -1,27 +1,49 @@
1
1
  import React from "react";
2
2
  import Button from '../ui/Button';
3
3
  import Icon from '../ui/Icon';
4
-
4
+ import dayjs from 'dayjs';
5
5
  type Props = {
6
6
  meeting: MeetingCardType
7
7
 
8
8
  }
9
9
  const MeetingCard = ({ meeting }: Props) => {
10
10
 
11
- const handleJoin = () => {
12
-
13
- }
14
-
15
11
  return (
16
- <div className="wy-attachments">
17
- <a className="wy-attachment" href={meeting.join_url} target="_blank">
18
- <div className="wy-attachment-icon" title="Zoom meeting"><Icon.UI name="zoom" color="#4a8cff" size={4} /></div>
19
- <div className="wy-attachment-content">
20
- <div className="wy-attachment-title">Zoom meeting</div>
21
- <div className="wy-attachment-meta">Meeting ID: {`${meeting.provider_id.substring(0,3)}-${meeting.provider_id.substring(3,6)}-${meeting.provider_id.substring(6)}`}</div>
22
- <Button.UI className="wy-button-primary">Join meeting</Button.UI>
12
+ <div className="wy-list">
13
+ {meeting.ended_at &&
14
+ <div className="wy-item wy-meeting">
15
+ <Icon.UI name="zoom" size={4} color="#cccccc"/>
16
+ <div className="wy-item-body">
17
+ <div className="wy-item-title">Zoom meeting</div>
18
+ <div className="wy-item-body">
19
+ <div>Ended {dayjs.utc(meeting.ended_at).tz(dayjs.tz.guess()).fromNow()}</div>
20
+ {meeting.recording_url &&
21
+ <div className="wy-meeting-actions">
22
+ <a href={meeting.recording_url} target="_blank" className="wy-button wy-button-primary">Play recording</a>
23
+ </div>
24
+ }
25
+
26
+ </div>
27
+ </div>
23
28
  </div>
24
- </a>
29
+ }
30
+
31
+ {!meeting.ended_at &&
32
+ <a className="wy-item wy-meeting" href={meeting.join_url} target="_blank">
33
+ <Icon.UI name="zoom" color="#4a8cff" size={4} />
34
+ <div className="wy-item-body">
35
+ <div className="wy-item-title">Zoom meeting</div>
36
+ <div className="wy-item-body">
37
+ <div>ID: {`${meeting.provider_id.substring(0, 3)}-${meeting.provider_id.substring(3, 6)}-${meeting.provider_id.substring(6)}`}</div>
38
+ <div className="wy-meeting-actions">
39
+ <Button.UI className="wy-button-primary">Join meeting</Button.UI>
40
+ </div>
41
+
42
+ </div>
43
+ </div>
44
+ </a>
45
+ }
46
+
25
47
  </div>
26
48
 
27
49
  )
@@ -22,7 +22,7 @@ const Meetings = ({ onMeetingAdded }: Props) => {
22
22
  return () => {
23
23
  window.removeEventListener("message", createMeeting);
24
24
  }
25
- }, [])
25
+ }, [onMeetingAdded])
26
26
 
27
27
  const createMeeting = async (e: any) => {
28
28
 
@@ -11,12 +11,12 @@ import MeetingCard from './MeetingCard';
11
11
  import usePreview from '../hooks/usePreview';
12
12
  import classNames from 'classnames';
13
13
 
14
- const Message: FC<MessageProps> = ({ id, html, temp, me, avatar, name, created_at, attachments, meeting, parentId, reactions, seenBy }) => {
14
+ const Message: FC<MessageProps> = ({ id, html, temp, me, avatar, name, created_at, created_by, attachments, meeting, parentId, reactions, seenBy, chatRoom }) => {
15
15
 
16
16
  const { open, close } = usePreview(attachments);
17
17
 
18
- var images = attachments?.filter((a: AttachmentType) => a.kind === "image" && a.thumbnail_url);
19
- var files = attachments?.filter((a: AttachmentType) => a.kind !== "image" || !a.thumbnail_url);
18
+ let images = attachments?.filter((a: AttachmentType) => a.kind === "image" && a.thumbnail_url);
19
+ let files = attachments?.filter((a: AttachmentType) => a.kind !== "image" || !a.thumbnail_url);
20
20
 
21
21
  const date = dayjs.utc(created_at).tz(dayjs.tz.guess());
22
22
 
@@ -35,50 +35,50 @@ const Message: FC<MessageProps> = ({ id, html, temp, me, avatar, name, created_a
35
35
  )}
36
36
  <div className="wy-message-content">
37
37
  <div className="wy-message-meta">
38
+ {chatRoom && !me &&
39
+ <span>{created_by} · </span>
40
+ }
38
41
  <time dateTime={created_at} title={date.format('LLLL')}>{date.fromNow()}</time>
39
42
  </div>
40
- <div className="wy-message-content-row">
41
- <div className="wy-message-bubble">
42
- {temp &&
43
- <div className="wy-message-text">{html}</div>
44
- }
45
- {!temp &&
46
- <>
47
- {images && !!images.length && <ImageGrid>
48
- {images.map((a: AttachmentType) =>
49
- <Image onClick={(e) => handlePreviewClick(e, a.id)} key={a.id} src={a.download_url} previewSrc={a.preview_url} width={a.width} height={a.height} />
50
- )}
51
- </ImageGrid>}
52
-
53
- {html && <div className="wy-message-text" dangerouslySetInnerHTML={{ __html: joypixels.shortnameToUnicode(html || "") }}></div>}
54
-
55
- {meeting &&
56
- <MeetingCard meeting={meeting} />
57
- }
58
-
59
- {files && !!files.length && <div className="wy-attachments">
60
- {files.map((a: AttachmentType) =>
61
- <Attachment key={a.id} name={a.name} previewFormat={a.kind} provider={a.provider} url={a.download_url} previewUrl={a.provider ? a.external_url : a.preview_url} mediaType={a.media_type} kind={a.kind} size={a.size} />
62
- )}
63
- </div>}
64
- </>
65
-
66
- }
67
- </div>
68
- <div className="wy-message-buttons">
69
- {!temp && <ReactionsMenu id={id} reactions={reactions} />}
70
- </div>
43
+
44
+ <div className="wy-message-bubble">
45
+ {temp &&
46
+ <div className="wy-content">{html}</div>
47
+ }
48
+ {!temp &&
49
+ <>
50
+ {images && !!images.length && <ImageGrid>
51
+ {images.map((a: AttachmentType) =>
52
+ <Image onClick={(e) => handlePreviewClick(e, a.id)} key={a.id} src={a.download_url} previewSrc={a.preview_url} width={a.width} height={a.height} />
53
+ )}
54
+ </ImageGrid>}
55
+
56
+ {html && <div className="wy-content" dangerouslySetInnerHTML={{ __html: joypixels.shortnameToUnicode(html || "") }}></div>}
57
+
58
+ {meeting &&
59
+ <MeetingCard meeting={meeting} />
60
+ }
61
+
62
+ {files && !!files.length && <div className="wy-list-items wy-attachments">
63
+ {files.map((a: AttachmentType) =>
64
+ <Attachment key={a.id} onClick={(e) => handlePreviewClick(e, a.id)} name={a.name} previewFormat={a.kind} provider={a.provider} url={a.download_url} previewUrl={a.provider ? a.external_url : a.preview_url} mediaType={a.media_type} kind={a.kind} size={a.size} />
65
+ )}
66
+ </div>}
67
+ <div className="wy-reactions-line">
68
+ <div className="wy-reactions">
69
+ <ReactionsList id={id} parentId={parentId} reactions={reactions} />
70
+ </div>
71
+ {!temp && <ReactionsMenu id={id} reactions={reactions} />}
72
+ </div>
73
+ </>
74
+ }
71
75
  </div>
72
76
 
73
- {!temp && (
74
- <div className="wy-reactions">
75
- <ReactionsList id={id} parentId={parentId} reactions={reactions} />
76
- </div>
77
- )}
78
-
77
+
78
+
79
79
  </div>
80
80
 
81
-
81
+
82
82
  </div>
83
83
  <SeenBy id={id} parentId={parentId} seenBy={seenBy} createdAt={created_at} />
84
84
  </>
@@ -17,11 +17,13 @@ type Props = {
17
17
  id: number,
18
18
  members: MembersResult | undefined,
19
19
  displayName?: string,
20
- avatarUrl?: string
20
+ avatarUrl?: string,
21
+ lastMessageId: number | null,
22
+ chatRoom: boolean
21
23
  }
22
24
 
23
- const Messages = ({ id, members, displayName, avatarUrl }: Props) => {
24
- var reverseScroller:IntersectionObserver | null;
25
+ const Messages = ({ id, members, displayName, avatarUrl, lastMessageId, chatRoom }: Props) => {
26
+ var reverseScroller: IntersectionObserver | null;
25
27
 
26
28
  const { user } = useContext(UserContext);
27
29
 
@@ -31,7 +33,7 @@ const Messages = ({ id, members, displayName, avatarUrl }: Props) => {
31
33
  const readMoreRef = useRef<any>();
32
34
  const messagesEndRef = useRef<any>();
33
35
  const [resolveScrollerFetch, setResolveScrollerFetch] = useState<Function | null>()
34
-
36
+
35
37
  const { dispatch, on, events } = useEvents();
36
38
 
37
39
  const { isLoading, isError, data, error, fetchNextPage, hasNextPage, isFetching, isFetchingNextPage } = useMessages(id, {});
@@ -44,7 +46,6 @@ const Messages = ({ id, members, displayName, avatarUrl }: Props) => {
44
46
  useLayoutEffect(() => {
45
47
  //if (id && !isLoading && !isLoadingMembers && !isLoadingConversation) {
46
48
  if (id && !isLoading) {
47
- //console.log("useLayoutEffect scroller", id)
48
49
  // scroll to bottom when selecting a conversation
49
50
  scrollParentToBottom(messagesEndRef.current);
50
51
 
@@ -63,7 +64,7 @@ const Messages = ({ id, members, displayName, avatarUrl }: Props) => {
63
64
  })
64
65
  }
65
66
  })
66
-
67
+
67
68
  } else {
68
69
  reverseScroller?.disconnect();
69
70
  reverseScroller = null;
@@ -85,60 +86,63 @@ const Messages = ({ id, members, displayName, avatarUrl }: Props) => {
85
86
  }, [data]);
86
87
 
87
88
  useEffect(() => {
89
+ // mark conversation as read
90
+ if (id && lastMessageId) {
91
+ readMessageMutation.mutate({ id: id, read: true, messageId: lastMessageId })
92
+ }
93
+ }, [id, lastMessageId])
88
94
 
95
+ useEffect(() => {
89
96
  if (id) {
90
-
91
- window.addEventListener('focus', handleFocus, false)
92
-
93
- // mark conversation as read
94
- readMessageMutation.mutate({ id: id, read: true })
95
-
96
- client?.subscribe(`a${id}`, "message-inserted", handleRealtimeMessage);
97
- client?.subscribe(`a${id}`, "conversation-read", handleRealtimeSeenBy);
98
- client?.subscribe(`a${id}`, "reaction-inserted", handleRealtimeReactionInserted);
99
- client?.subscribe(`a${id}`, "reaction-deleted", handleRealtimeReactionDeleted);
97
+ client?.subscribe(`a${id}`, "message_created", handleRealtimeMessage);
98
+ client?.subscribe(`a${id}`, "conversation_marked", handleRealtimeSeenBy);
99
+ client?.subscribe(`a${id}`, "reaction_added", handleRealtimeReactionInserted);
100
+ client?.subscribe(`a${id}`, "reaction_removed", handleRealtimeReactionDeleted);
100
101
  }
101
102
 
102
103
  return () => {
103
- window.removeEventListener('focus', handleFocus, false)
104
+
105
+ //window.removeEventListener('focus', handleFocus, false);
104
106
 
105
107
  if (id) {
106
108
  // remove additional pages in cache. Only get first page
107
109
  let qd = queryClient.getQueryData(["messages", id]);
108
-
110
+
109
111
  if (qd) {
110
-
112
+
111
113
  queryClient.setQueryData(["messages", id], (data: any) => ({
112
- pages: data?.pages.slice(0,1),
113
- pageParams: [undefined]
114
- }));
114
+ pages: data?.pages.slice(0, 1),
115
+ pageParams: [undefined]
116
+ }));
115
117
  }
116
118
 
117
- client?.unsubscribe(`a${id}`, "message-inserted", handleRealtimeMessage);
118
- client?.unsubscribe(`a${id}`, "conversation-read", handleRealtimeSeenBy);
119
- client?.unsubscribe(`a${id}`, "reaction-inserted", handleRealtimeReactionInserted);
120
- client?.unsubscribe(`a${id}`, "reaction-deleted", handleRealtimeReactionDeleted);
119
+ client?.unsubscribe(`a${id}`, "message_created", handleRealtimeMessage);
120
+ client?.unsubscribe(`a${id}`, "conversation_marked", handleRealtimeSeenBy);
121
+ client?.unsubscribe(`a${id}`, "reaction_added", handleRealtimeReactionInserted);
122
+ client?.unsubscribe(`a${id}`, "reaction_removed", handleRealtimeReactionDeleted);
121
123
  }
122
124
  }
123
125
  }, [id]);
124
126
 
125
- const handleRealtimeReactionInserted = useCallback((data: ReactionType) => {
126
- dispatch("reaction-inserted", data);
127
+
128
+ const handleRealtimeReactionInserted = useCallback((realtimeEvent: RealtimeReaction) => {
129
+ dispatch("reaction_added_" + realtimeEvent.entity.id, realtimeEvent);
127
130
  }, [id]);
128
131
 
129
- const handleRealtimeReactionDeleted = useCallback((data: ReactionType) => {
130
- dispatch("reaction-deleted", data);
132
+ const handleRealtimeReactionDeleted = useCallback((realtimeEvent: RealtimeReaction) => {
133
+ dispatch("reaction_deleted_" + realtimeEvent.entity.id, realtimeEvent);
131
134
  }, [id]);
132
135
 
133
136
  // handle new message from post form
134
137
  const handleNewMessage = (text: string, attachments: [], meetings: []) => {
135
138
  addMessageMutation.mutate({ id: id, text: text, userId: user.id, attachments: attachments, meetings: meetings }, {
136
- onSuccess: () => { requestAnimationFrame(() => scrollParentToBottom(messagesEndRef.current, true))}
137
- });
138
-
139
- // mark conversation as read
140
- setTimeout(() => { readMessageMutation.mutate({ id: id, read: true }) }, 1000);
139
+ onSuccess: (data: MessageType) => {
140
+ // mark conversation as read
141
+ readMessageMutation.mutate({ id: id, read: true, messageId: data.id });
141
142
 
143
+ requestAnimationFrame(() => scrollParentToBottom(messagesEndRef.current, true))
144
+ }
145
+ });
142
146
 
143
147
  requestAnimationFrame(() => scrollParentToBottom(readMoreRef.current, true));
144
148
  }
@@ -146,7 +150,7 @@ const Messages = ({ id, members, displayName, avatarUrl }: Props) => {
146
150
  const handleRealtimeSeenBy = async (data: any) => {
147
151
  let isAtBottom = isParentAtBottom(readMoreRef.current);
148
152
  // how to do this better?
149
- queryClient.invalidateQueries(["members", id])
153
+ queryClient.invalidateQueries(["members", id]);
150
154
 
151
155
  if (isAtBottom) {
152
156
  requestAnimationFrame(() => scrollParentToBottom(readMoreRef.current, true));
@@ -154,11 +158,14 @@ const Messages = ({ id, members, displayName, avatarUrl }: Props) => {
154
158
  }
155
159
 
156
160
  // real time insert-message handler
157
- const handleRealtimeMessage = useCallback((message: MessageType) => {
158
- if (message.app_id !== id || message.created_by.id === user.id) return;
161
+ const handleRealtimeMessage = useCallback((realtimeEvent: RealtimeMessage) => {
162
+ if (realtimeEvent.message.app_id !== id || realtimeEvent.message.created_by_id === user.id) return;
163
+
164
+ // set created_by
165
+ realtimeEvent.message.created_by = realtimeEvent.actor;
159
166
 
160
167
  // mark conversation as read
161
- readMessageMutation.mutate({ id: id, read: true })
168
+ readMessageMutation.mutate({ id: id, read: true, messageId: realtimeEvent.message.id })
162
169
 
163
170
  const previousData = queryClient.getQueryData<any>(['messages', id]);
164
171
 
@@ -166,13 +173,13 @@ const Messages = ({ id, members, displayName, avatarUrl }: Props) => {
166
173
  let isAtBottom = isParentAtBottom(readMoreRef.current);
167
174
 
168
175
  const newPagesArray = previousData.pages.map((page: any, i: number) => {
169
- // remove temp message
176
+ // add realtime message
177
+
170
178
  if (i === 0) {
171
179
  page.data = [
172
180
  ...page.data,
173
- message
181
+ realtimeEvent.message
174
182
  ]
175
-
176
183
  }
177
184
  return page;
178
185
 
@@ -191,15 +198,9 @@ const Messages = ({ id, members, displayName, avatarUrl }: Props) => {
191
198
 
192
199
  }, [id]);
193
200
 
194
- const handleFocus = useCallback(() => {
195
- if (!id) return;
196
-
197
- readMessageMutation.mutate({ id: id, read: true })
198
- }, [id]);
199
-
200
201
  let messageHeader = <div className="wy-avatar-header">
201
202
  {avatarUrl && displayName && <Avatar src={avatarUrl} name={displayName} id={id} size={128} /> || ''}
202
- {displayName && <div className="wy-avatar-display-name">{displayName}</div> || ''}
203
+ {displayName && <div className="wy-headline">{displayName}</div> || ''}
203
204
  </div>;
204
205
 
205
206
  let loadMoreButton = <Button.UI onClick={() => fetchNextPage()} disabled={!hasNextPage || isFetchingNextPage} className="wy-message-readmore">Load more</Button.UI>;
@@ -207,19 +208,19 @@ const Messages = ({ id, members, displayName, avatarUrl }: Props) => {
207
208
  let messages = (
208
209
  <>
209
210
  <div className="wy-message-readmore" ref={readMoreRef}>
210
- {isFetchingNextPage
211
- ? 'Loading more...'
212
- : hasNextPage
213
- ? loadMoreButton
214
- : messageHeader}
215
-
211
+ {isFetchingNextPage
212
+ ? 'Loading more...'
213
+ : hasNextPage
214
+ ? loadMoreButton
215
+ : messageHeader}
216
+
216
217
  </div>
217
218
  {data && members && data.pages && data.pages.map((group, i) => {
218
219
  // Reverse key since page loading is reversed
219
220
  return <React.Fragment key={data.pages.length - i}>
220
221
  {
221
222
  group.data?.map((item: MessageType) => {
222
-
223
+
223
224
  return <Message
224
225
  key={item.id}
225
226
  id={item.id}
@@ -229,15 +230,15 @@ const Messages = ({ id, members, displayName, avatarUrl }: Props) => {
229
230
  avatar={item.created_by.avatar_url}
230
231
  name={item.created_by.display_name}
231
232
  created_at={item.created_at}
233
+ created_by={item.created_by.display_name}
232
234
  attachments={item.attachments}
233
235
  meeting={item.meeting}
234
236
  parentId={id}
235
237
  reactions={item.reactions}
238
+ chatRoom={chatRoom}
236
239
  //reactions_count={item.reactions_count}
237
- seenBy={members.data.length > 0 ? members.data.filter((member) => {
238
- const hasRead = member.read_at >= item.created_at;
239
- const nothingLaterRead = !data.pages.map((p) => p.data).flat().find((message: MessageType) => { return message.id > item.id && member.read_at >= message.created_at });
240
- return hasRead && nothingLaterRead && member.id !== user.id;
240
+ seenBy={(members.data && members.data.length > 0) ? members.data.filter((member) => {
241
+ return member.marked_id === item.id && member.id !== user.id;
241
242
  }) : []}
242
243
  />
243
244
  })
@@ -260,7 +261,7 @@ const Messages = ({ id, members, displayName, avatarUrl }: Props) => {
260
261
  <div id="container" className="wy-messages">
261
262
  {messages}
262
263
  </div>
263
- <div className="wy-message-editor">
264
+ <div className="wy-footerbar wy-footerbar-sticky wy-message-editor wy-message-editor-bottom">
264
265
  <ConversationForm key={id} conversationId={id} handleInsert={handleNewMessage} />
265
266
  </div>
266
267
  </>
@@ -4,8 +4,13 @@ import Conversation from './Conversation';
4
4
  import ConversationList from './ConversationList';
5
5
  import { Messenger } from '../types/Messenger';
6
6
  import { WeavyContext } from '../contexts/WeavyContext';
7
+ import classNames from 'classnames';
7
8
 
8
- const Messenger: FC<Messenger> = () => {
9
+ type Props = {
10
+ className?: string,
11
+ }
12
+
13
+ const Messenger: FC<Messenger> = ({ className }: Props) => {
9
14
 
10
15
  const { client } = useContext(WeavyContext);
11
16
 
@@ -15,7 +20,7 @@ const Messenger: FC<Messenger> = () => {
15
20
 
16
21
  return (
17
22
  <MessengerProvider>
18
- <div className="wy-messenger-provider">
23
+ <div className={classNames("wy-messenger-provider", className)}>
19
24
 
20
25
  <div className="wy-messenger-sidebar wy-scroll-y">
21
26
  <ConversationList />
@@ -29,7 +29,7 @@ const NewConversation = () => {
29
29
  <Button.UI onClick={handleOpen}><Icon.UI name="plus" /></Button.UI>
30
30
 
31
31
  <Overlay.UI isOpen={modalOpen} className="wy-modal">
32
- <header className="wy-appbars">
32
+ <header className="wy-appbars" data-adjust-scrollbar-top>
33
33
  <nav className="wy-appbar">
34
34
  <Button.UI onClick={handleClose}><Icon.UI name='close' /></Button.UI>
35
35
  <div className="wy-appbar-text">Create conversation</div>