@weavy/uikit-react 13.0.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 (243) hide show
  1. package/changelog.md +24 -0
  2. package/dist/cjs/index.js +3 -3
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/types/components/Chat.d.ts +1 -1
  5. package/dist/cjs/types/components/Messages.d.ts +3 -1
  6. package/dist/cjs/types/hooks/useConversations.d.ts +1 -1
  7. package/dist/cjs/types/hooks/useMutateMessage.d.ts +1 -1
  8. package/dist/cjs/types/hooks/useMutateRead.d.ts +1 -0
  9. package/dist/cjs/types/types/Chat.d.ts +1 -0
  10. package/dist/cjs/types/types/Message.d.ts +2 -0
  11. package/dist/cjs/types/types/types.d.ts +47 -4
  12. package/dist/cjs/types/ui/Spinner.d.ts +2 -1
  13. package/dist/css/weavy-chat.css +1540 -954
  14. package/dist/css/weavy-messenger.css +1901 -1298
  15. package/dist/css/weavy.css +1696 -1093
  16. package/dist/esm/index.js +3 -3
  17. package/dist/esm/index.js.map +1 -1
  18. package/dist/esm/types/components/Chat.d.ts +1 -1
  19. package/dist/esm/types/components/Messages.d.ts +3 -1
  20. package/dist/esm/types/hooks/useConversations.d.ts +1 -1
  21. package/dist/esm/types/hooks/useMutateMessage.d.ts +1 -1
  22. package/dist/esm/types/hooks/useMutateRead.d.ts +1 -0
  23. package/dist/esm/types/types/Chat.d.ts +1 -0
  24. package/dist/esm/types/types/Message.d.ts +2 -0
  25. package/dist/esm/types/types/types.d.ts +47 -4
  26. package/dist/esm/types/ui/Spinner.d.ts +2 -1
  27. package/dist/index.d.ts +2 -1
  28. package/package.json +2 -2
  29. package/src/client/WeavyClient.ts +12 -17
  30. package/src/components/Attachment.tsx +5 -5
  31. package/src/components/Chat.tsx +6 -5
  32. package/src/components/Conversation.tsx +26 -20
  33. package/src/components/ConversationBadge.tsx +7 -5
  34. package/src/components/ConversationForm.tsx +1 -1
  35. package/src/components/ConversationList.tsx +59 -11
  36. package/src/components/ConversationListItem.tsx +71 -54
  37. package/src/components/FileBrowser.tsx +53 -50
  38. package/src/components/MeetingCard.tsx +35 -13
  39. package/src/components/Meetings.tsx +1 -1
  40. package/src/components/Message.tsx +41 -41
  41. package/src/components/Messages.tsx +61 -60
  42. package/src/components/Messenger.tsx +7 -2
  43. package/src/components/NewConversation.tsx +1 -1
  44. package/src/components/PdfViewer.tsx +5 -5
  45. package/src/components/Preview.tsx +2 -2
  46. package/src/components/Reactions.tsx +11 -5
  47. package/src/components/SearchUsers.tsx +19 -9
  48. package/src/components/SeenBy.tsx +13 -7
  49. package/src/components/Typing.tsx +11 -12
  50. package/src/contexts/UserContext.tsx +1 -1
  51. package/src/contexts/WeavyContext.tsx +3 -3
  52. package/src/hooks/useConversations.ts +15 -5
  53. package/src/hooks/useMutateMessage.ts +1 -5
  54. package/src/hooks/useMutateRead.ts +5 -3
  55. package/src/hooks/usePresence.ts +2 -3
  56. package/src/hooks/useReactions.ts +11 -12
  57. package/src/scss/theme/_alert.scss +61 -63
  58. package/src/scss/theme/_appbar.scss +105 -30
  59. package/src/scss/theme/_avatar.scss +23 -28
  60. package/src/scss/theme/_badge.scss +26 -18
  61. package/src/scss/theme/_buttons.scss +107 -52
  62. package/src/scss/theme/_card.scss +102 -4
  63. package/src/scss/theme/_checkbox.scss +16 -20
  64. package/src/scss/theme/_code-vscode-dark.scss +3 -3
  65. package/src/scss/theme/_code-vscode-light.scss +3 -3
  66. package/src/scss/theme/_code.scss +0 -2
  67. package/src/scss/theme/_comment-editor-cm.scss +97 -0
  68. package/src/scss/theme/_comment-editor.scss +129 -0
  69. package/src/scss/theme/_comments.scss +66 -0
  70. package/src/scss/theme/_content.scss +33 -5
  71. package/src/scss/theme/_conversations.scss +19 -78
  72. package/src/scss/theme/_dropdown.scss +102 -15
  73. package/src/scss/theme/_embed.scss +135 -0
  74. package/src/scss/theme/_facepile.scss +11 -0
  75. package/src/scss/theme/_filebrowser.scss +1 -1
  76. package/src/scss/theme/_files.scss +76 -47
  77. package/src/scss/theme/_grid.scss +8 -0
  78. package/src/scss/theme/_icons.scss +155 -19
  79. package/src/scss/theme/_image-grid.scss +7 -10
  80. package/src/scss/theme/_input.scss +160 -0
  81. package/src/scss/theme/_item.scss +169 -0
  82. package/src/scss/theme/_list.scss +57 -0
  83. package/src/scss/theme/_meeting.scss +11 -0
  84. package/src/scss/theme/_message-editor-cm.scss +95 -0
  85. package/src/scss/theme/_message-editor.scss +65 -19
  86. package/src/scss/theme/_messages.scss +51 -105
  87. package/src/scss/theme/_meta.scss +12 -0
  88. package/src/scss/theme/_overlays.scss +31 -76
  89. package/src/scss/theme/_pager.scss +5 -1
  90. package/src/scss/theme/_pane.scss +13 -2
  91. package/src/scss/theme/_panels.scss +33 -28
  92. package/src/scss/theme/_picker-list.scss +5 -3
  93. package/src/scss/theme/_placeholder.scss +19 -0
  94. package/src/scss/theme/_poll.scss +49 -0
  95. package/src/scss/theme/_post-editor-cm.scss +100 -0
  96. package/src/scss/theme/_post-editor.scss +127 -0
  97. package/src/scss/theme/_post.scss +83 -0
  98. package/src/scss/theme/_preview-code.scss +11 -2
  99. package/src/scss/theme/_preview-embed.scss +8 -2
  100. package/src/scss/theme/_preview-image.scss +8 -26
  101. package/src/scss/theme/_preview-media.scss +1 -0
  102. package/src/scss/theme/_preview-pdf.scss +10 -15
  103. package/src/scss/theme/_preview.scss +57 -79
  104. package/src/scss/theme/_reactions.scss +48 -17
  105. package/src/scss/theme/_sheet.scss +59 -0
  106. package/src/scss/theme/_sidebar.scss +86 -0
  107. package/src/scss/theme/_spinner.scss +11 -7
  108. package/src/scss/theme/_tab.scss +72 -0
  109. package/src/scss/theme/_tables.scss +70 -23
  110. package/src/scss/theme/_toasts.scss +56 -26
  111. package/src/scss/theme/_type.scss +41 -0
  112. package/src/scss/theme/{mixins → base}/_backdrop.scss +0 -0
  113. package/src/scss/theme/{bootstrap/mixins → base}/_breakpoints.scss +9 -0
  114. package/src/scss/theme/base/_colors.scss +315 -0
  115. package/src/scss/theme/base/_md.scss +19 -0
  116. package/src/scss/theme/base/_palette.scss +130 -0
  117. package/src/scss/theme/{mixins → base}/_position.scss +5 -5
  118. package/src/scss/theme/base/_reboot.scss +51 -0
  119. package/src/scss/theme/base/_scroll.scss +180 -0
  120. package/src/scss/theme/base/_svg.scss +49 -0
  121. package/src/scss/theme/base/_text.scss +23 -0
  122. package/src/scss/theme/base/_vars.scss +203 -0
  123. package/src/scss/theme/{fonts → base/fonts}/_fontmapping-roboto.scss +0 -0
  124. package/src/scss/theme/{fonts → base/fonts}/_fontmapping-segoe-ui.scss +0 -0
  125. package/src/scss/theme/base/fonts/_index.scss +2 -0
  126. package/src/scss/weavy-chat.scss +10 -4
  127. package/src/scss/weavy-messenger.scss +37 -21
  128. package/src/types/Chat.ts +2 -1
  129. package/src/types/Message.ts +3 -1
  130. package/src/types/types.ts +56 -5
  131. package/src/ui/Icon.tsx +1 -1
  132. package/src/ui/Spinner.tsx +3 -2
  133. package/src/utils/infiniteScroll.js +11 -2
  134. package/src/utils/postal-parent.js +398 -0
  135. package/src/utils/promise.js +187 -0
  136. package/src/utils/scrollbarDetection.js +68 -9
  137. package/src/utils/utils.js +547 -0
  138. package/src/scss/theme/_attachments.scss +0 -74
  139. package/src/scss/theme/_cm-editor.scss +0 -42
  140. package/src/scss/theme/_colors.scss +0 -520
  141. package/src/scss/theme/_config.scss +0 -6
  142. package/src/scss/theme/_inputs.scss +0 -28
  143. package/src/scss/theme/_nav.scss +0 -52
  144. package/src/scss/theme/_palette.scss +0 -165
  145. package/src/scss/theme/_preview-icon.scss +0 -41
  146. package/src/scss/theme/_reboot.scss +0 -41
  147. package/src/scss/theme/_root.scss +0 -2
  148. package/src/scss/theme/_scroll.scss +0 -55
  149. package/src/scss/theme/_search.scss +0 -68
  150. package/src/scss/theme/_turbo.scss +0 -17
  151. package/src/scss/theme/_variables.scss +0 -139
  152. package/src/scss/theme/bootstrap/_accordion.scss +0 -146
  153. package/src/scss/theme/bootstrap/_alert.scss +0 -71
  154. package/src/scss/theme/bootstrap/_badge.scss +0 -38
  155. package/src/scss/theme/bootstrap/_breadcrumb.scss +0 -40
  156. package/src/scss/theme/bootstrap/_button-group.scss +0 -142
  157. package/src/scss/theme/bootstrap/_buttons.scss +0 -186
  158. package/src/scss/theme/bootstrap/_card.scss +0 -234
  159. package/src/scss/theme/bootstrap/_carousel.scss +0 -229
  160. package/src/scss/theme/bootstrap/_close.scss +0 -40
  161. package/src/scss/theme/bootstrap/_containers.scss +0 -41
  162. package/src/scss/theme/bootstrap/_dropdown.scss +0 -248
  163. package/src/scss/theme/bootstrap/_forms.scss +0 -9
  164. package/src/scss/theme/bootstrap/_functions.scss +0 -302
  165. package/src/scss/theme/bootstrap/_grid.scss +0 -33
  166. package/src/scss/theme/bootstrap/_helpers.scss +0 -10
  167. package/src/scss/theme/bootstrap/_images.scss +0 -42
  168. package/src/scss/theme/bootstrap/_list-group.scss +0 -191
  169. package/src/scss/theme/bootstrap/_maps.scss +0 -54
  170. package/src/scss/theme/bootstrap/_mixins.scss +0 -43
  171. package/src/scss/theme/bootstrap/_modal.scss +0 -237
  172. package/src/scss/theme/bootstrap/_nav.scss +0 -172
  173. package/src/scss/theme/bootstrap/_navbar.scss +0 -276
  174. package/src/scss/theme/bootstrap/_offcanvas.scss +0 -143
  175. package/src/scss/theme/bootstrap/_pagination.scss +0 -109
  176. package/src/scss/theme/bootstrap/_placeholders.scss +0 -51
  177. package/src/scss/theme/bootstrap/_popover.scss +0 -196
  178. package/src/scss/theme/bootstrap/_progress.scss +0 -59
  179. package/src/scss/theme/bootstrap/_reboot.scss +0 -610
  180. package/src/scss/theme/bootstrap/_root.scss +0 -73
  181. package/src/scss/theme/bootstrap/_spinners.scss +0 -85
  182. package/src/scss/theme/bootstrap/_tables.scss +0 -164
  183. package/src/scss/theme/bootstrap/_toasts.scss +0 -70
  184. package/src/scss/theme/bootstrap/_tooltip.scss +0 -120
  185. package/src/scss/theme/bootstrap/_transitions.scss +0 -27
  186. package/src/scss/theme/bootstrap/_type.scss +0 -106
  187. package/src/scss/theme/bootstrap/_utilities.scss +0 -647
  188. package/src/scss/theme/bootstrap/_variables.scss +0 -1633
  189. package/src/scss/theme/bootstrap/forms/_floating-labels.scss +0 -74
  190. package/src/scss/theme/bootstrap/forms/_form-check.scss +0 -175
  191. package/src/scss/theme/bootstrap/forms/_form-control.scss +0 -194
  192. package/src/scss/theme/bootstrap/forms/_form-range.scss +0 -91
  193. package/src/scss/theme/bootstrap/forms/_form-select.scss +0 -71
  194. package/src/scss/theme/bootstrap/forms/_form-text.scss +0 -11
  195. package/src/scss/theme/bootstrap/forms/_input-group.scss +0 -129
  196. package/src/scss/theme/bootstrap/forms/_labels.scss +0 -36
  197. package/src/scss/theme/bootstrap/forms/_validation.scss +0 -12
  198. package/src/scss/theme/bootstrap/helpers/_clearfix.scss +0 -3
  199. package/src/scss/theme/bootstrap/helpers/_color-bg.scss +0 -10
  200. package/src/scss/theme/bootstrap/helpers/_colored-links.scss +0 -12
  201. package/src/scss/theme/bootstrap/helpers/_position.scss +0 -36
  202. package/src/scss/theme/bootstrap/helpers/_ratio.scss +0 -26
  203. package/src/scss/theme/bootstrap/helpers/_stacks.scss +0 -15
  204. package/src/scss/theme/bootstrap/helpers/_stretched-link.scss +0 -15
  205. package/src/scss/theme/bootstrap/helpers/_text-truncation.scss +0 -7
  206. package/src/scss/theme/bootstrap/helpers/_visually-hidden.scss +0 -8
  207. package/src/scss/theme/bootstrap/helpers/_vr.scss +0 -8
  208. package/src/scss/theme/bootstrap/mixins/_alert.scss +0 -15
  209. package/src/scss/theme/bootstrap/mixins/_backdrop.scss +0 -14
  210. package/src/scss/theme/bootstrap/mixins/_banner.scss +0 -9
  211. package/src/scss/theme/bootstrap/mixins/_border-radius.scss +0 -78
  212. package/src/scss/theme/bootstrap/mixins/_box-shadow.scss +0 -18
  213. package/src/scss/theme/bootstrap/mixins/_buttons.scss +0 -70
  214. package/src/scss/theme/bootstrap/mixins/_caret.scss +0 -64
  215. package/src/scss/theme/bootstrap/mixins/_clearfix.scss +0 -9
  216. package/src/scss/theme/bootstrap/mixins/_color-scheme.scss +0 -7
  217. package/src/scss/theme/bootstrap/mixins/_container.scss +0 -11
  218. package/src/scss/theme/bootstrap/mixins/_deprecate.scss +0 -10
  219. package/src/scss/theme/bootstrap/mixins/_forms.scss +0 -152
  220. package/src/scss/theme/bootstrap/mixins/_gradients.scss +0 -47
  221. package/src/scss/theme/bootstrap/mixins/_grid.scss +0 -151
  222. package/src/scss/theme/bootstrap/mixins/_image.scss +0 -16
  223. package/src/scss/theme/bootstrap/mixins/_list-group.scss +0 -24
  224. package/src/scss/theme/bootstrap/mixins/_lists.scss +0 -7
  225. package/src/scss/theme/bootstrap/mixins/_pagination.scss +0 -10
  226. package/src/scss/theme/bootstrap/mixins/_reset-text.scss +0 -17
  227. package/src/scss/theme/bootstrap/mixins/_resize.scss +0 -6
  228. package/src/scss/theme/bootstrap/mixins/_table-variants.scss +0 -24
  229. package/src/scss/theme/bootstrap/mixins/_text-truncate.scss +0 -8
  230. package/src/scss/theme/bootstrap/mixins/_transition.scss +0 -26
  231. package/src/scss/theme/bootstrap/mixins/_utilities.scss +0 -97
  232. package/src/scss/theme/bootstrap/mixins/_visually-hidden.scss +0 -29
  233. package/src/scss/theme/bootstrap/utilities/_api.scss +0 -47
  234. package/src/scss/theme/bootstrap/vendor/_rfs.scss +0 -354
  235. package/src/scss/theme/bs/_badge.scss +0 -20
  236. package/src/scss/theme/bs/_buttons.scss +0 -185
  237. package/src/scss/theme/bs/_dropdown.scss +0 -86
  238. package/src/scss/theme/bs/_forms.scss +0 -161
  239. package/src/scss/theme/bs/_list-group.scss +0 -73
  240. package/src/scss/theme/bs/_tables.scss +0 -46
  241. package/src/scss/theme/fonts/_index.scss +0 -2
  242. package/src/scss/theme/mixins/_palette.scss +0 -165
  243. package/src/scss/theme/mixins/_scrollbar.scss +0 -110
@@ -27,22 +27,40 @@ const ConversationListItem = ({ item, refetchConversations }: ConversationListIt
27
27
 
28
28
  const ChatRoom = "edb400ac-839b-45a7-b2a8-6a01820d1c44";
29
29
 
30
- const handleClick = (e: React.MouseEvent<HTMLAnchorElement>, id: any) => {
31
- e.preventDefault();
32
- setSelectedConversationId(id);
30
+ const handleClick = (e: React.MouseEvent<HTMLDivElement>, id: any) => {
31
+ if (!e.defaultPrevented) {
32
+ e.preventDefault();
33
+ setSelectedConversationId(id);
34
+ }
33
35
  }
34
36
 
35
- const handleAppUpdated = useCallback((data: ConversationType) => {
36
- if (data.id !== item.id) return;
37
+ const handleAppUpdated = useCallback((realtimeEvent: RealtimeApp) => {
38
+ if (realtimeEvent.app.id !== item.id) return;
37
39
  refetchConversations();
38
40
 
39
- }, [item.id])
41
+ }, [item.id]);
42
+
43
+ const handleMessageCreated = useCallback((realtimeEvent: RealtimeMessage) => {
44
+ if (realtimeEvent.message.app_id !== item.id) return;
45
+ refetchConversations();
46
+
47
+ }, [item.id]);
48
+
49
+ const handleMemberAdded = useCallback((realtimeEvent: RealtimeMember) => {
50
+ if (realtimeEvent.app.id !== item.id) return;
51
+ refetchConversations();
52
+
53
+ }, [item.id]);
40
54
 
41
55
  useEffect(() => {
42
- client?.subscribe(`a${item.id}`, "app-updated", handleAppUpdated);
56
+ client?.subscribe(`a${item.id}`, "app_updated", handleAppUpdated);
57
+ client?.subscribe(`a${item.id}`, "message_created", handleMessageCreated);
58
+ client?.subscribe(`a${item.id}`, "member_added", handleMemberAdded);
43
59
 
44
60
  return () => {
45
- client?.unsubscribe(`a${item.id}`, "app-updated", handleAppUpdated);
61
+ client?.unsubscribe(`a${item.id}`, "app_updated", handleAppUpdated);
62
+ client?.unsubscribe(`a${item.id}`, "message_created", handleMessageCreated);
63
+ client?.unsubscribe(`a${item.id}`, "member_added", handleMemberAdded);
46
64
  }
47
65
  }, [item.id])
48
66
 
@@ -50,12 +68,12 @@ const ConversationListItem = ({ item, refetchConversations }: ConversationListIt
50
68
 
51
69
  const handleUnread = (e: React.MouseEvent<HTMLAnchorElement>) => {
52
70
  e.preventDefault();
53
- readMutation.mutate({ id: item.id, read: false });
71
+ readMutation.mutate({ id: item.id, read: false, messageId: null });
54
72
  }
55
73
 
56
74
  const handleRead = (e: React.MouseEvent<HTMLAnchorElement>) => {
57
75
  e.preventDefault();
58
- readMutation.mutate({ id: item.id, read: true });
76
+ readMutation.mutate({ id: item.id, read: true, messageId: item.last_message.id });
59
77
  }
60
78
 
61
79
  const handlePin = (e: React.MouseEvent<HTMLAnchorElement>) => {
@@ -78,18 +96,18 @@ const ConversationListItem = ({ item, refetchConversations }: ConversationListIt
78
96
  // }
79
97
 
80
98
  return (
81
- <div className={classNames('wy-conversation', {"wy-unread": item.is_unread})} key={item.id}>
82
- <a className={classNames('wy-conversation-link', { "wy-active": selectedConversationId === item.id})} href="#" onClick={(e) => handleClick(e, item.id)}>
83
- <Avatar src={item.avatar_url} id={otherId || -1} presence={item.type !== ChatRoom ? "away" : ""} name={item.display_name} />
84
-
85
- <div className="wy-conversation-body">
86
- <div className="wy-conversation-header">
87
- <div className="wy-conversation-title">{item.display_name}</div>
88
- {item.last_message &&
89
- <time className="wy-conversation-time" dateTime={item.last_message.created_at.toString()} title={date.format('LLLL')}>{date.fromNow()}</time>
90
- }
91
- </div>
92
- <div className="wy-conversation-summary">
99
+ <div className={classNames('wy-item wy-item-lg wy-item-hover wy-conversation', {"wy-unread": item.is_unread, "wy-active": selectedConversationId === item.id})} key={item.id} onClick={(e) => handleClick(e, item.id)}>
100
+ <Avatar src={item.avatar_url} id={otherId || -1} presence={item.type !== ChatRoom ? "away" : ""} name={item.display_name} />
101
+
102
+ <div className="wy-item-body">
103
+ <div className="wy-item-row">
104
+ <div className="wy-item-title">{item.display_name}</div>
105
+ {item.last_message &&
106
+ <time className="wy-meta" dateTime={item.last_message.created_at.toString()} title={date.format('LLLL')}>{date.fromNow()}</time>
107
+ }
108
+ </div>
109
+ <div className="wy-item-row">
110
+ <div className="wy-item-text">
93
111
  <Typing id={item.id} context="listitem">
94
112
 
95
113
  {item.last_message?.html &&
@@ -108,44 +126,43 @@ const ConversationListItem = ({ item, refetchConversations }: ConversationListIt
108
126
 
109
127
  </Typing>
110
128
  </div>
111
- </div>
112
- </a>
129
+
113
130
 
114
- <div className="wy-conversation-actions">
115
- {item.is_pinned &&
116
- <Button.UI onClick={handleUnpin}>
117
- <Icon.UI name="pin" size={.75} />
118
- </Button.UI>
119
-
120
- }
121
-
122
- <Dropdown.UI directionX='left'>
123
- <>
124
- {item.is_unread &&
125
- <Dropdown.Item onClick={handleRead}>Mark as read</Dropdown.Item>
126
- }
127
- {!item.is_unread &&
128
- <Dropdown.Item onClick={handleUnread}>Mark as unread</Dropdown.Item>
129
- }
130
- </>
131
- <>
131
+ </div>
132
+ </div>
133
+ <div className="wy-item-actions wy-item-actions-bottom">
132
134
  {item.is_pinned &&
133
- <Dropdown.Item onClick={handleUnpin}>Unpin</Dropdown.Item>
134
- }
135
- {!item.is_pinned &&
136
- <Dropdown.Item onClick={handlePin}>Pin</Dropdown.Item>
137
- }
138
- </>
139
- {item.type === ChatRoom &&
140
- <Dropdown.Item onClick={handleLeaveConversation}>Leave conversation</Dropdown.Item>
141
- }
135
+ <Button.UI onClick={handleUnpin}>
136
+ <Icon.UI name="pin" size={1/1.5} />
137
+ </Button.UI>
142
138
 
143
- {/* <li><Button.UI onClick={handleStar}>Star</Button.UI></li> */}
144
- </Dropdown.UI>
139
+ }
145
140
 
141
+ <Dropdown.UI directionX='left'>
142
+ <>
143
+ {item.is_unread &&
144
+ <Dropdown.Item onClick={handleRead}>Mark as read</Dropdown.Item>
145
+ }
146
+ {!item.is_unread &&
147
+ <Dropdown.Item onClick={handleUnread}>Mark as unread</Dropdown.Item>
148
+ }
149
+ </>
150
+ <>
151
+ {item.is_pinned &&
152
+ <Dropdown.Item onClick={handleUnpin}>Unpin</Dropdown.Item>
153
+ }
154
+ {!item.is_pinned &&
155
+ <Dropdown.Item onClick={handlePin}>Pin</Dropdown.Item>
156
+ }
157
+ </>
158
+ {item.type === ChatRoom &&
159
+ <Dropdown.Item onClick={handleLeaveConversation}>Leave conversation</Dropdown.Item>
160
+ }
146
161
 
162
+ {/* <li><Button.UI onClick={handleStar}>Star</Button.UI></li> */}
163
+ </Dropdown.UI>
147
164
 
148
- </div>
165
+ </div>
149
166
  </div>
150
167
  )
151
168
  }
@@ -1,9 +1,11 @@
1
- import React, { useContext, useEffect } from "react";
1
+ import React, { useContext, useEffect, useState, useRef, useCallback } from "react";
2
2
  import { WeavyContext } from "../contexts/WeavyContext";
3
3
  import Button from '../ui/Button';
4
+ import Spinner from '../ui/Spinner';
4
5
  import Icon from '../ui/Icon';
5
6
  import useMutateExternalBlobs from '../hooks/useMutateExternalBlobs';
6
- import { UserContext } from "../contexts/UserContext";
7
+ import Overlay from '../ui/Overlay';
8
+ import WeavyPostal from "../utils/postal-parent";
7
9
 
8
10
  type Props = {
9
11
  onFileAdded: Function
@@ -12,72 +14,73 @@ type Props = {
12
14
  const FileBrowser = ({ onFileAdded }: Props) => {
13
15
 
14
16
  const { options } = useContext(WeavyContext);
15
- const { user } = useContext(UserContext);
16
-
17
+ const [modalOpen, setModalOpen] = useState(false);
18
+ const [visible, setVisible] = useState(false);
19
+ const [frameSrc, setFrameSrc] = useState("");
17
20
  const addExternalBlobs = useMutateExternalBlobs();
21
+ const fileBrowserUrl = options?.filebrowserUrl || "";
22
+
23
+ const frameRef = useCallback((node: HTMLIFrameElement | null) => {
24
+ if (node !== null && node.contentWindow != null) {
25
+ WeavyPostal.registerContentWindow(node.contentWindow.self, "weavy-filebrowser", "wy-filebrowser", new URL(fileBrowserUrl).origin);
26
+ }
27
+ }, []);
18
28
 
19
29
  useEffect(() => {
20
- window.addEventListener("message", handleFilebrowserMessage);
30
+ const origin = window.top?.document.location.origin;
31
+
32
+ const filebrowserSrc = fileBrowserUrl + "?origin=" + origin + "&v=X&t=" + Date.now().toString() + "&weavyId=wy-filebrowser";
21
33
 
34
+ setFrameSrc(filebrowserSrc)
35
+
36
+ WeavyPostal.on("add-external-blobs", handleFiles);
37
+ WeavyPostal.on("request:file-browser-close", handleClose);
22
38
 
23
39
  return () => {
24
- window.removeEventListener("message", handleFilebrowserMessage);
40
+ WeavyPostal.off("add-external-blobs", handleFiles);
41
+ WeavyPostal.off("request:file-browser-close", handleClose);
25
42
  }
26
- }, []);
43
+ }, [onFileAdded]);
27
44
 
28
- const handleFilebrowserMessage = async (e: any) => {
29
- const messageData = e.data;
30
-
31
- switch (messageData.name) {
32
- case "addExternalBlobs":
33
- var result = await addExternalBlobs.mutateAsync({ blobs: messageData.blobs });
34
- onFileAdded(result);
35
- closeFilebrowser();
36
- break;
37
- case "file-browser-close":
38
- closeFilebrowser();
39
- break;
40
- }
45
+ const toggleModal = (open: boolean) => {
46
+ setModalOpen(open);
41
47
  }
42
48
 
43
- const closeFilebrowser = () => {
44
- let fb = document.getElementById("weavy-filebrowser");
45
- if (fb) {
46
- fb.style.display = "none";
47
- }
49
+ const handleFiles = async (e: Event, message: any) => {
50
+ var result = await addExternalBlobs.mutateAsync({ blobs: message.blobs });
51
+ onFileAdded(result);
52
+ closeFilebrowser();
48
53
  }
49
54
 
50
- const openFilebrowser = () => {
51
- let fb = document.getElementById("weavy-filebrowser");
52
-
53
- if (!fb) {
54
- const origin = window.top?.document.location.origin;
55
- const fileBrowserUrl = options?.filebrowserUrl;
56
- const filebrowserSrc = fileBrowserUrl + "?origin=" + origin + "&v=X&t=" + Date.now().toString() + "&weavyId=-1";
57
-
58
- let $filebrowserFrame = document.createElement("iframe");
59
- $filebrowserFrame.id = "weavy-filebrowser";
60
- $filebrowserFrame.name = "weavy-filebrowser";
61
- $filebrowserFrame.src = filebrowserSrc;
62
- $filebrowserFrame.className = "wy-filebrowser-frame";
63
- $filebrowserFrame.style.cssText = "position: fixed; top: 0; left: 0; height: 100%; width: 100%; background: rgba(1,1,1,.4); z-index: 10000; display:none"
64
-
65
- window.top?.document.body.appendChild($filebrowserFrame);
55
+ const handleClose = () => {
56
+ closeFilebrowser();
57
+ }
66
58
 
67
- $filebrowserFrame.addEventListener('load', () => {
68
- $filebrowserFrame.style.display = "block";
69
- });
59
+ const closeFilebrowser = () => {
60
+ setModalOpen(false);
61
+ setVisible(false);
62
+ }
70
63
 
71
- } else {
72
- fb.style.display = "block";
73
- }
64
+ const handleFrameLoad = () => {
65
+ setVisible(true);
74
66
  }
75
67
 
76
68
  return (
77
69
  <>
78
- {options?.enableCloudFiles &&
79
- <Button.UI onClick={openFilebrowser} title="Add file from cloud"><Icon.UI name="cloud" /></Button.UI>
80
- }
70
+ {options?.enableCloudFiles &&
71
+ <>
72
+ <Button.UI onClick={() => toggleModal(true)} title="Add file from cloud"><Icon.UI name="cloud" /></Button.UI>
73
+
74
+ <Overlay.UI isOpen={modalOpen} className="wy-modal wy-panel wy-loaded">
75
+ {!visible &&
76
+ <Spinner.UI overlay={true} />
77
+ }
78
+
79
+ <iframe ref={frameRef} onLoad={handleFrameLoad} src={frameSrc} className="wy-panel-frame" id="weavy-filebrowser" name="weavy-filebrowser"></iframe>
80
+
81
+ </Overlay.UI>
82
+ </>
83
+ }
81
84
  </>
82
85
  )
83
86
  }
@@ -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} 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} />
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
  </>