@ethora/chat-component-rn 26.7.4 → 26.7.5

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 (288) hide show
  1. package/CHANGELOG.md +0 -54
  2. package/README.md +8 -31
  3. package/lib/commonjs/assets/icons.js +2 -7
  4. package/lib/commonjs/assets/icons.js.map +1 -1
  5. package/lib/commonjs/components/Header/HeaderRoomList.js +6 -20
  6. package/lib/commonjs/components/Header/HeaderRoomList.js.map +1 -1
  7. package/lib/commonjs/components/MainComponents/ChatRoom.js +14 -36
  8. package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
  9. package/lib/commonjs/components/MainComponents/MessageList.js +23 -7
  10. package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
  11. package/lib/commonjs/components/MainComponents/ProfileImagePlaceholder.js +13 -14
  12. package/lib/commonjs/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
  13. package/lib/commonjs/components/MainComponents/RoomList.js +32 -62
  14. package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
  15. package/lib/commonjs/components/Menu/HeaderRoomListMenu.js +98 -309
  16. package/lib/commonjs/components/Menu/HeaderRoomListMenu.js.map +1 -1
  17. package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js +110 -320
  18. package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
  19. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +213 -552
  20. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  21. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +2 -6
  22. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  23. package/lib/commonjs/components/Modals/Modal/Modal.js +0 -8
  24. package/lib/commonjs/components/Modals/Modal/Modal.js.map +1 -1
  25. package/lib/commonjs/components/Modals/NewChatModal/ModalContent.js +1 -2
  26. package/lib/commonjs/components/Modals/NewChatModal/ModalContent.js.map +1 -1
  27. package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js +104 -202
  28. package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
  29. package/lib/commonjs/components/Modals/NewChatModal/UpdNewChatModal.js +0 -8
  30. package/lib/commonjs/components/Modals/NewChatModal/UpdNewChatModal.js.map +1 -1
  31. package/lib/commonjs/components/Modals/SelectUsersModal/SelectUsersModal.js +2 -4
  32. package/lib/commonjs/components/Modals/SelectUsersModal/SelectUsersModal.js.map +1 -1
  33. package/lib/commonjs/components/Modals/UserProfileModal/EditUserModal.js +21 -7
  34. package/lib/commonjs/components/Modals/UserProfileModal/EditUserModal.js.map +1 -1
  35. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +244 -507
  36. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  37. package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js +46 -74
  38. package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
  39. package/lib/commonjs/components/Modals/styledModalComponents.js +2 -9
  40. package/lib/commonjs/components/Modals/styledModalComponents.js.map +1 -1
  41. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js +7 -17
  42. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js.map +1 -1
  43. package/lib/commonjs/components/styled/SendInput.js +11 -80
  44. package/lib/commonjs/components/styled/SendInput.js.map +1 -1
  45. package/lib/commonjs/components/styled/StyledComponents.js +3 -9
  46. package/lib/commonjs/components/styled/StyledComponents.js.map +1 -1
  47. package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js +4 -11
  48. package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
  49. package/lib/commonjs/context/xmppProvider.js +35 -6
  50. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  51. package/lib/commonjs/helpers/updateMessagesTillLast.js +40 -12
  52. package/lib/commonjs/helpers/updateMessagesTillLast.js.map +1 -1
  53. package/lib/commonjs/hooks/useChatRoomFocus.js +9 -3
  54. package/lib/commonjs/hooks/useChatRoomFocus.js.map +1 -1
  55. package/lib/commonjs/hooks/useLogout.js +5 -0
  56. package/lib/commonjs/hooks/useLogout.js.map +1 -1
  57. package/lib/commonjs/hooks/useSendMessage.js +50 -23
  58. package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
  59. package/lib/commonjs/i18n/strings.js +1 -121
  60. package/lib/commonjs/i18n/strings.js.map +1 -1
  61. package/lib/commonjs/main.js +0 -6
  62. package/lib/commonjs/main.js.map +1 -1
  63. package/lib/commonjs/networking/api-requests/user.api.js +0 -59
  64. package/lib/commonjs/networking/api-requests/user.api.js.map +1 -1
  65. package/lib/commonjs/networking/outboundQueue.js +18 -0
  66. package/lib/commonjs/networking/outboundQueue.js.map +1 -1
  67. package/lib/commonjs/networking/stanzaHandlers.js +10 -1
  68. package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
  69. package/lib/commonjs/networking/xmppClient.js +107 -7
  70. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  71. package/lib/commonjs/roomStore/chatSettingsSlice.js +1 -3
  72. package/lib/commonjs/roomStore/chatSettingsSlice.js.map +1 -1
  73. package/lib/commonjs/roomStore/roomsSlice.js +22 -3
  74. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  75. package/lib/module/assets/icons.js +1 -6
  76. package/lib/module/assets/icons.js.map +1 -1
  77. package/lib/module/components/Header/HeaderRoomList.js +6 -20
  78. package/lib/module/components/Header/HeaderRoomList.js.map +1 -1
  79. package/lib/module/components/MainComponents/ChatRoom.js +14 -36
  80. package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
  81. package/lib/module/components/MainComponents/MessageList.js +24 -8
  82. package/lib/module/components/MainComponents/MessageList.js.map +1 -1
  83. package/lib/module/components/MainComponents/ProfileImagePlaceholder.js +13 -14
  84. package/lib/module/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
  85. package/lib/module/components/MainComponents/RoomList.js +32 -62
  86. package/lib/module/components/MainComponents/RoomList.js.map +1 -1
  87. package/lib/module/components/Menu/HeaderRoomListMenu.js +101 -311
  88. package/lib/module/components/Menu/HeaderRoomListMenu.js.map +1 -1
  89. package/lib/module/components/Modals/AttachSheet/AttachSheet.js +113 -311
  90. package/lib/module/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
  91. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +217 -555
  92. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  93. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +2 -6
  94. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  95. package/lib/module/components/Modals/Modal/Modal.js +1 -9
  96. package/lib/module/components/Modals/Modal/Modal.js.map +1 -1
  97. package/lib/module/components/Modals/NewChatModal/ModalContent.js +1 -2
  98. package/lib/module/components/Modals/NewChatModal/ModalContent.js.map +1 -1
  99. package/lib/module/components/Modals/NewChatModal/NewChatModal.js +106 -205
  100. package/lib/module/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
  101. package/lib/module/components/Modals/NewChatModal/UpdNewChatModal.js +0 -8
  102. package/lib/module/components/Modals/NewChatModal/UpdNewChatModal.js.map +1 -1
  103. package/lib/module/components/Modals/SelectUsersModal/SelectUsersModal.js +2 -4
  104. package/lib/module/components/Modals/SelectUsersModal/SelectUsersModal.js.map +1 -1
  105. package/lib/module/components/Modals/UserProfileModal/EditUserModal.js +23 -9
  106. package/lib/module/components/Modals/UserProfileModal/EditUserModal.js.map +1 -1
  107. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +248 -509
  108. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  109. package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js +48 -76
  110. package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
  111. package/lib/module/components/Modals/styledModalComponents.js +2 -9
  112. package/lib/module/components/Modals/styledModalComponents.js.map +1 -1
  113. package/lib/module/components/RoomComponents/ChatRoomItem.js +7 -17
  114. package/lib/module/components/RoomComponents/ChatRoomItem.js.map +1 -1
  115. package/lib/module/components/styled/SendInput.js +12 -81
  116. package/lib/module/components/styled/SendInput.js.map +1 -1
  117. package/lib/module/components/styled/StyledComponents.js +3 -9
  118. package/lib/module/components/styled/StyledComponents.js.map +1 -1
  119. package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js +4 -11
  120. package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
  121. package/lib/module/context/xmppProvider.js +35 -6
  122. package/lib/module/context/xmppProvider.js.map +1 -1
  123. package/lib/module/helpers/updateMessagesTillLast.js +41 -13
  124. package/lib/module/helpers/updateMessagesTillLast.js.map +1 -1
  125. package/lib/module/hooks/useChatRoomFocus.js +9 -3
  126. package/lib/module/hooks/useChatRoomFocus.js.map +1 -1
  127. package/lib/module/hooks/useLogout.js +5 -0
  128. package/lib/module/hooks/useLogout.js.map +1 -1
  129. package/lib/module/hooks/useSendMessage.js +51 -24
  130. package/lib/module/hooks/useSendMessage.js.map +1 -1
  131. package/lib/module/i18n/strings.js +1 -121
  132. package/lib/module/i18n/strings.js.map +1 -1
  133. package/lib/module/main.js +1 -1
  134. package/lib/module/main.js.map +1 -1
  135. package/lib/module/networking/api-requests/user.api.js +0 -56
  136. package/lib/module/networking/api-requests/user.api.js.map +1 -1
  137. package/lib/module/networking/outboundQueue.js +17 -0
  138. package/lib/module/networking/outboundQueue.js.map +1 -1
  139. package/lib/module/networking/stanzaHandlers.js +10 -1
  140. package/lib/module/networking/stanzaHandlers.js.map +1 -1
  141. package/lib/module/networking/xmppClient.js +107 -7
  142. package/lib/module/networking/xmppClient.js.map +1 -1
  143. package/lib/module/roomStore/chatSettingsSlice.js +1 -3
  144. package/lib/module/roomStore/chatSettingsSlice.js.map +1 -1
  145. package/lib/module/roomStore/roomsSlice.js +20 -2
  146. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  147. package/lib/typescript/assets/icons.d.ts +0 -16
  148. package/lib/typescript/assets/icons.d.ts.map +1 -1
  149. package/lib/typescript/components/Header/HeaderRoomList.d.ts.map +1 -1
  150. package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
  151. package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
  152. package/lib/typescript/components/MainComponents/ProfileImagePlaceholder.d.ts.map +1 -1
  153. package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
  154. package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts +0 -3
  155. package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts.map +1 -1
  156. package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts +0 -9
  157. package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts.map +1 -1
  158. package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts +0 -10
  159. package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
  160. package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
  161. package/lib/typescript/components/Modals/Modal/Modal.d.ts.map +1 -1
  162. package/lib/typescript/components/Modals/NewChatModal/ModalContent.d.ts +2 -4
  163. package/lib/typescript/components/Modals/NewChatModal/ModalContent.d.ts.map +1 -1
  164. package/lib/typescript/components/Modals/NewChatModal/NewChatModal.d.ts +1 -1
  165. package/lib/typescript/components/Modals/NewChatModal/NewChatModal.d.ts.map +1 -1
  166. package/lib/typescript/components/Modals/NewChatModal/UpdNewChatModal.d.ts.map +1 -1
  167. package/lib/typescript/components/Modals/SelectUsersModal/SelectUsersModal.d.ts +1 -6
  168. package/lib/typescript/components/Modals/SelectUsersModal/SelectUsersModal.d.ts.map +1 -1
  169. package/lib/typescript/components/Modals/UserProfileModal/EditUserModal.d.ts.map +1 -1
  170. package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts +0 -16
  171. package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
  172. package/lib/typescript/components/Modals/UserSettingsModal/UserSettingsModal.d.ts +0 -1
  173. package/lib/typescript/components/Modals/UserSettingsModal/UserSettingsModal.d.ts.map +1 -1
  174. package/lib/typescript/components/Modals/styledModalComponents.d.ts.map +1 -1
  175. package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts.map +1 -1
  176. package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
  177. package/lib/typescript/components/styled/StyledComponents.d.ts.map +1 -1
  178. package/lib/typescript/components/styled/StyledInputComponents/StyledInputComponents.d.ts.map +1 -1
  179. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  180. package/lib/typescript/helpers/updateMessagesTillLast.d.ts.map +1 -1
  181. package/lib/typescript/hooks/useChatRoomFocus.d.ts.map +1 -1
  182. package/lib/typescript/hooks/useLogout.d.ts.map +1 -1
  183. package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
  184. package/lib/typescript/i18n/strings.d.ts.map +1 -1
  185. package/lib/typescript/main.d.ts +1 -1
  186. package/lib/typescript/main.d.ts.map +1 -1
  187. package/lib/typescript/networking/api-requests/user.api.d.ts +0 -27
  188. package/lib/typescript/networking/api-requests/user.api.d.ts.map +1 -1
  189. package/lib/typescript/networking/outboundQueue.d.ts +16 -0
  190. package/lib/typescript/networking/outboundQueue.d.ts.map +1 -1
  191. package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
  192. package/lib/typescript/networking/xmppClient.d.ts +33 -1
  193. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  194. package/lib/typescript/roomStore/chatSettingsSlice.d.ts.map +1 -1
  195. package/lib/typescript/roomStore/roomsSlice.d.ts +18 -1
  196. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  197. package/lib/typescript/types/models/room.model.d.ts +15 -0
  198. package/lib/typescript/types/models/room.model.d.ts.map +1 -1
  199. package/lib/typescript/types/types.d.ts +20 -20
  200. package/lib/typescript/types/types.d.ts.map +1 -1
  201. package/package.json +1 -6
  202. package/src/assets/icons.tsx +9 -48
  203. package/src/components/Header/HeaderRoomList.tsx +5 -20
  204. package/src/components/MainComponents/ChatRoom.tsx +20 -38
  205. package/src/components/MainComponents/MessageList.tsx +24 -8
  206. package/src/components/MainComponents/ProfileImagePlaceholder.tsx +14 -21
  207. package/src/components/MainComponents/RoomList.tsx +34 -65
  208. package/src/components/Menu/HeaderRoomListMenu.tsx +71 -310
  209. package/src/components/Modals/AttachSheet/AttachSheet.tsx +97 -331
  210. package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +279 -598
  211. package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +2 -4
  212. package/src/components/Modals/Modal/Modal.tsx +0 -7
  213. package/src/components/Modals/NewChatModal/ModalContent.tsx +3 -6
  214. package/src/components/Modals/NewChatModal/NewChatModal.tsx +117 -219
  215. package/src/components/Modals/NewChatModal/UpdNewChatModal.tsx +1 -12
  216. package/src/components/Modals/SelectUsersModal/SelectUsersModal.tsx +4 -14
  217. package/src/components/Modals/UserProfileModal/EditUserModal.tsx +25 -9
  218. package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +307 -617
  219. package/src/components/Modals/UserSettingsModal/UserSettingsModal.tsx +58 -75
  220. package/src/components/Modals/styledModalComponents.tsx +2 -9
  221. package/src/components/RoomComponents/ChatRoomItem.tsx +7 -14
  222. package/src/components/styled/SendInput.tsx +12 -83
  223. package/src/components/styled/StyledComponents.ts +3 -9
  224. package/src/components/styled/StyledInputComponents/StyledInputComponents.tsx +4 -11
  225. package/src/context/xmppProvider.tsx +41 -8
  226. package/src/helpers/updateMessagesTillLast.tsx +42 -17
  227. package/src/hooks/useChatRoomFocus.ts +11 -3
  228. package/src/hooks/useLogout.tsx +7 -0
  229. package/src/hooks/useSendMessage.tsx +60 -24
  230. package/src/i18n/strings.ts +1 -121
  231. package/src/main.ts +1 -1
  232. package/src/networking/api-requests/user.api.ts +0 -71
  233. package/src/networking/outboundQueue.ts +29 -0
  234. package/src/networking/stanzaHandlers.ts +9 -1
  235. package/src/networking/xmppClient.ts +118 -7
  236. package/src/roomStore/chatSettingsSlice.ts +1 -3
  237. package/src/roomStore/roomsSlice.ts +20 -2
  238. package/src/types/models/room.model.ts +15 -0
  239. package/src/types/types.ts +20 -22
  240. package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js +0 -226
  241. package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js.map +0 -1
  242. package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js +0 -556
  243. package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js.map +0 -1
  244. package/lib/commonjs/components/Modals/ProfileHeader/ProfileMenu.js +0 -210
  245. package/lib/commonjs/components/Modals/ProfileHeader/ProfileMenu.js.map +0 -1
  246. package/lib/commonjs/helpers/getChatBackground.js +0 -23
  247. package/lib/commonjs/helpers/getChatBackground.js.map +0 -1
  248. package/lib/commonjs/helpers/mediaLibraryRuntime.js +0 -31
  249. package/lib/commonjs/helpers/mediaLibraryRuntime.js.map +0 -1
  250. package/lib/commonjs/helpers/pickImageAsset.js +0 -68
  251. package/lib/commonjs/helpers/pickImageAsset.js.map +0 -1
  252. package/lib/commonjs/helpers/sheetGestures.js +0 -32
  253. package/lib/commonjs/helpers/sheetGestures.js.map +0 -1
  254. package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js +0 -223
  255. package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js.map +0 -1
  256. package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js +0 -548
  257. package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js.map +0 -1
  258. package/lib/module/components/Modals/ProfileHeader/ProfileMenu.js +0 -205
  259. package/lib/module/components/Modals/ProfileHeader/ProfileMenu.js.map +0 -1
  260. package/lib/module/helpers/getChatBackground.js +0 -18
  261. package/lib/module/helpers/getChatBackground.js.map +0 -1
  262. package/lib/module/helpers/mediaLibraryRuntime.js +0 -25
  263. package/lib/module/helpers/mediaLibraryRuntime.js.map +0 -1
  264. package/lib/module/helpers/pickImageAsset.js +0 -63
  265. package/lib/module/helpers/pickImageAsset.js.map +0 -1
  266. package/lib/module/helpers/sheetGestures.js +0 -26
  267. package/lib/module/helpers/sheetGestures.js.map +0 -1
  268. package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts +0 -9
  269. package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts.map +0 -1
  270. package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts +0 -75
  271. package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts.map +0 -1
  272. package/lib/typescript/components/Modals/ProfileHeader/ProfileMenu.d.ts +0 -25
  273. package/lib/typescript/components/Modals/ProfileHeader/ProfileMenu.d.ts.map +0 -1
  274. package/lib/typescript/helpers/getChatBackground.d.ts +0 -15
  275. package/lib/typescript/helpers/getChatBackground.d.ts.map +0 -1
  276. package/lib/typescript/helpers/mediaLibraryRuntime.d.ts +0 -3
  277. package/lib/typescript/helpers/mediaLibraryRuntime.d.ts.map +0 -1
  278. package/lib/typescript/helpers/pickImageAsset.d.ts +0 -27
  279. package/lib/typescript/helpers/pickImageAsset.d.ts.map +0 -1
  280. package/lib/typescript/helpers/sheetGestures.d.ts +0 -20
  281. package/lib/typescript/helpers/sheetGestures.d.ts.map +0 -1
  282. package/src/components/Modals/ChatProfileModal/ReportChatModal.tsx +0 -244
  283. package/src/components/Modals/ProfileHeader/ProfileHeader.tsx +0 -615
  284. package/src/components/Modals/ProfileHeader/ProfileMenu.tsx +0 -217
  285. package/src/helpers/getChatBackground.ts +0 -18
  286. package/src/helpers/mediaLibraryRuntime.ts +0 -25
  287. package/src/helpers/pickImageAsset.ts +0 -68
  288. package/src/helpers/sheetGestures.ts +0 -25
@@ -1,78 +1,43 @@
1
- /** @format */
2
-
3
- import React, { useEffect, useMemo, useRef, useState } from 'react';
4
- import {
5
- Alert,
6
- Animated,
7
- Keyboard,
8
- Linking,
9
- Pressable,
10
- StyleSheet,
11
- Text,
12
- TextInput,
13
- TouchableOpacity,
14
- View,
15
- } from 'react-native';
16
- import { useDispatch, useSelector } from 'react-redux';
17
- import * as ImagePicker from 'expo-image-picker';
1
+ import React, { useEffect, useMemo, useState } from 'react';
18
2
  import { useFileToken } from '../../../hooks/useFileToken';
19
3
  import { appendFileToken } from '../../../helpers/secureFileUrl';
20
- import { ModalContainerFullScreen } from '../styledModalComponents';
4
+ import {
5
+ CenterContainer,
6
+ UserInfo,
7
+ UserName,
8
+ UserStatus,
9
+ ModalContainerFullScreen,
10
+ Label,
11
+ BorderedContainer,
12
+ LabelData,
13
+ Viewider,
14
+ Divider,
15
+ } from '../styledModalComponents';
16
+ import { Pressable, View, Text, ScrollView, Alert, Linking } from 'react-native';
17
+ import ModalHeaderComponent from '../ModalHeaderComponent';
21
18
  import { ProfileImagePlaceholder } from '../../MainComponents/ProfileImagePlaceholder';
19
+ import { useDispatch, useSelector } from 'react-redux';
22
20
  import { RootState, getActiveRoom } from '../../../roomStore';
23
21
  import { uploadFile } from '../../../networking/api-requests/auth.api';
24
22
  import { useXmppClient } from '../../../context/xmppProvider';
25
- import { deleteRoom, updateRoom } from '../../../roomStore/roomsSlice';
23
+ import { updateRoom } from '../../../roomStore/roomsSlice';
24
+ import * as ImagePicker from 'expo-image-picker';
26
25
  import Loader from '../../styled/Loader';
27
- import {
28
- AddNewIcon,
29
- DeleteIcon,
30
- EditIcon,
31
- LeaveIcon,
32
- ReportIcon,
33
- SearchIcon,
34
- } from '../../../assets/icons';
26
+ import Button from '../../styled/Button';
27
+ import { DeleteIcon, MoreIcon, QrIcon } from '../../../assets/icons';
28
+ import Switch from '../../MainComponents/Switch';
35
29
  import { useChatSettingState } from '../../../hooks/useChatSettingState';
36
30
  import { chatTextStyle } from '../../../helpers/typography';
37
31
  import { getElementFont } from '../../../helpers/getElementFont';
38
- import { getIconColor } from '../../../helpers/getIconColor';
39
32
  import { deleteRoomMember } from '../../../networking/api-requests/rooms.api';
40
33
  import { RoomMember } from '../../../types/models/room.model';
41
34
  import { setActiveModal, setSelectedUser } from '../../../roomStore/chatSettingsSlice';
42
35
  import { MODAL_TYPES } from '../../../helpers/constants/MODAL_TYPES';
36
+ import DropdownMenu, { MenuOption } from '../../DropdownMenu/DropdownMenu';
43
37
  import SelectUsersModal from '../SelectUsersModal/SelectUsersModal';
44
38
  import { useToast } from '../../../context/ToastContext';
45
- import { useT } from '../../../i18n/useT';
46
39
  import DeleteChatModal from './DeleteChatModal';
47
- import ReportChatModal from './ReportChatModal';
48
- import {
49
- ProfileHero,
50
- ProfileTopBar,
51
- HeroAction,
52
- useHeaderMetrics,
53
- } from '../ProfileHeader/ProfileHeader';
54
- import ProfileMenu, { ProfileMenuItem } from '../ProfileHeader/ProfileMenu';
55
40
 
56
- /**
57
- * Where the header should sit when search opens: tucked away at the
58
- * collapsed offset when the picture is still expanded, and left exactly
59
- * where it is when the user already scrolled it away.
60
- */
61
- export const searchScrollTarget = (
62
- isCollapsed: boolean,
63
- collapseDistance: number
64
- ): number | null => (isCollapsed ? null : collapseDistance);
65
-
66
- /** Two uppercase letters for a chat without a picture, same rule the
67
- * avatar placeholder uses for people. */
68
- export const chatInitials = (name?: string | null): string => {
69
- const words = (name || '').trim().split(/\s+/).filter(Boolean);
70
- const letters = (words.length >= 2
71
- ? [words[0][0], words[1][0]]
72
- : [words[0]?.[0], words[0]?.[1]]
73
- ).filter((c) => !!c && /[\p{L}\p{N}]/u.test(c));
74
- return letters.join('').toUpperCase();
75
- };
76
41
 
77
42
  interface ChatProfileModalProps {
78
43
  handleCloseModal: any;
@@ -81,38 +46,33 @@ interface ChatProfileModalProps {
81
46
  const ChatProfileModal: React.FC<ChatProfileModalProps> = ({
82
47
  handleCloseModal,
83
48
  }) => {
84
- const t = useT();
85
49
  const [loading, setLoading] = useState<boolean>(false);
86
- const [isDeleteOpen, setIsDeleteOpen] = useState(false);
87
- const [isReportOpen, setIsReportOpen] = useState(false);
88
- const [memberQuery, setMemberQuery] = useState('');
89
- const [isSearchOpen, setIsSearchOpen] = useState(false);
90
- // Measured, not guessed: this screen renders inside whatever frame the
91
- // host gives it (the demo app keeps its own tab bar above), so the
92
- // window height would overshoot.
93
- const [viewportHeight, setViewportHeight] = useState(0);
50
+ const [visible, setVisible] = useState<boolean>(false);
51
+ const [isModalOpen, setIsModalOpen] = useState(false);
94
52
 
95
53
  const { showToast } = useToast();
54
+
55
+ const chatMenuOptions = useMemo(
56
+ () => [
57
+ {
58
+ label: 'Delete chat',
59
+ icon: <DeleteIcon />,
60
+ onClick: () => {
61
+ setIsModalOpen(true);
62
+ },
63
+ styles: { color: 'red' },
64
+ },
65
+ ],
66
+ []
67
+ );
68
+
96
69
  const dispatch = useDispatch();
70
+
97
71
  const { client } = useXmppClient();
98
72
  const { user: stateUser, config } = useChatSettingState();
99
73
  const activeRoom = useSelector((state: RootState) => getActiveRoom(state));
100
74
  const fileToken = useFileToken();
101
75
 
102
- // Drives both the hero's parallax and the collapsed bar's fade-in. One
103
- // shared value, written natively by the ScrollView.
104
- const scrollY = useRef(new Animated.Value(0)).current;
105
- const scrollRef = useRef<any>(null);
106
- const searchInputRef = useRef<TextInput>(null);
107
- const { collapseDistance } = useHeaderMetrics();
108
- // `scrollY` is driven natively, so its value can't be read back with
109
- // addListener. The Animated.event's `listener` still fires on the JS
110
- // side, which is enough to know which state the header is in.
111
- const [isCollapsed, setIsCollapsed] = useState(false);
112
- // Set when search collapsed the header itself, so only then does
113
- // dismissing search (or the keyboard) expand it again.
114
- const collapsedForSearchRef = useRef(false);
115
-
116
76
  // Pull live member list from the MUC when the modal opens — REST
117
77
  // hydration only fills the *count* (item.participants /
118
78
  // item.members.length); the actual roster comes from a `getRoomMembers`
@@ -127,12 +87,6 @@ const ChatProfileModal: React.FC<ChatProfileModalProps> = ({
127
87
  }
128
88
  }, [client, activeRoom?.jid]);
129
89
 
130
- useEffect(() => {
131
- if (!activeRoom) {
132
- dispatch(setActiveModal(undefined));
133
- }
134
- }, [activeRoom, dispatch]);
135
-
136
90
  const onUpload = async () => {
137
91
  let loadingSet = false;
138
92
  try {
@@ -149,7 +103,7 @@ const ChatProfileModal: React.FC<ChatProfileModalProps> = ({
149
103
  'Photo library permission is needed to select images.',
150
104
  [
151
105
  {
152
- text: t('action.cancel'),
106
+ text: 'Cancel',
153
107
  onPress: () => setLoading(false),
154
108
  style: 'cancel',
155
109
  },
@@ -218,13 +172,7 @@ const ChatProfileModal: React.FC<ChatProfileModalProps> = ({
218
172
  }
219
173
  };
220
174
 
221
- const onRemoveIcon = () => {
222
- client?.setRoomImageStanza(activeRoom?.jid || '', '', 'icon', 'none');
223
- dispatch(updateRoom({ jid: activeRoom?.jid || '', updates: { icon: null } }));
224
- };
225
-
226
- const handleDeleteUser = async (user: RoomMember) => {
227
- const userId = user.xmppUsername;
175
+ const handleDeleteUser = async (userId: string) => {
228
176
  try {
229
177
  await deleteRoomMember({
230
178
  roomId: activeRoom?.jid?.split('@')[0] || '',
@@ -236,7 +184,7 @@ const ChatProfileModal: React.FC<ChatProfileModalProps> = ({
236
184
  jid: activeRoom?.jid || '',
237
185
  updates: {
238
186
  roomMembers: activeRoom?.roomMembers?.filter(
239
- (member) => member.xmppUsername !== userId
187
+ (user) => user.xmppUsername !== userId
240
188
  ),
241
189
  },
242
190
  })
@@ -259,19 +207,9 @@ const ChatProfileModal: React.FC<ChatProfileModalProps> = ({
259
207
  }
260
208
  };
261
209
 
262
- const confirmRemoveMember = (user: RoomMember) => {
263
- Alert.alert(
264
- t('modal.chatProfile.removeMember'),
265
- `${user.firstName} ${user.lastName}`.trim(),
266
- [
267
- { text: t('action.cancel'), style: 'cancel' },
268
- {
269
- text: t('action.delete'),
270
- style: 'destructive',
271
- onPress: () => handleDeleteUser(user),
272
- },
273
- ]
274
- );
210
+ const onRemoveClick = async () => {
211
+ client?.setRoomImageStanza(activeRoom?.jid || '', '', 'icon', 'none');
212
+ dispatch(updateRoom({ jid: activeRoom?.jid || '', updates: { icon: null } }));
275
213
  };
276
214
 
277
215
  const handleUserAvatarClick = (user: RoomMember): void => {
@@ -289,527 +227,270 @@ const ChatProfileModal: React.FC<ChatProfileModalProps> = ({
289
227
  );
290
228
  };
291
229
 
292
- // Leaving is XMPP-side (an unavailable presence to the MUC); dropping the
293
- // room from the store is what actually takes the user out of the chat in
294
- // the UI, and the `!activeRoom` effect above then closes this modal.
295
- const handleLeave = () => {
296
- Alert.alert(t('modal.leaveChat.title'), t('modal.leaveChat.description'), [
297
- { text: t('action.cancel'), style: 'cancel' },
230
+ const menuOptions = useMemo(
231
+ () => (userId: string) => [
298
232
  {
299
- text: t('action.leave'),
300
- style: 'destructive',
301
- onPress: () => {
302
- try {
303
- client?.leaveTheRoomStanza?.(activeRoom?.jid || '');
304
- } catch (error) {
305
- console.error('Failed to leave the room:', error);
306
- }
307
- dispatch(deleteRoom({ jid: activeRoom?.jid || '' }));
308
- handleCloseModal?.();
233
+ label: 'Appoint as an admin',
234
+ icon: null,
235
+ onClick: () => {
236
+ dispatch(setActiveModal(MODAL_TYPES.PROFILE));
237
+ console.log('Profile clicked');
309
238
  },
310
239
  },
311
- ]);
312
- };
313
-
314
- const isModerator = activeRoom?.role === 'moderator';
315
- const canEditIcon =
316
- !config?.disableChatInfo?.disableIconEdit && activeRoom?.role !== 'participant';
317
- const canAddMembers = isModerator && activeRoom?.type === 'group';
318
- const canDeleteChat = isModerator && activeRoom?.type !== 'private';
319
- const hasIcon = !!activeRoom?.icon;
320
-
321
- const scrollHeaderTo = (y: number) =>
322
- scrollRef.current?.scrollTo?.({ y, animated: true });
323
-
324
- // Opening search from an expanded header tucks the picture away so the
325
- // results and the keyboard have room; from an already-collapsed header
326
- // it just opens the field. Whatever it collapsed, it puts back.
327
- const openMemberSearch = () => {
328
- const target = searchScrollTarget(isCollapsed, collapseDistance);
329
- if (target !== null) {
330
- collapsedForSearchRef.current = true;
331
- scrollHeaderTo(target);
332
- }
333
- setIsSearchOpen(true);
334
- setTimeout(() => searchInputRef.current?.focus(), 50);
335
- };
336
-
337
- const restoreHeader = () => {
338
- if (!collapsedForSearchRef.current) {return;}
339
- collapsedForSearchRef.current = false;
340
- scrollHeaderTo(0);
341
- };
342
-
343
- const closeMemberSearch = () => {
344
- setMemberQuery('');
345
- setIsSearchOpen(false);
346
- Keyboard.dismiss();
347
- restoreHeader();
348
- };
349
-
350
- // Putting the keyboard away is the other way out of search, so it
351
- // restores the header too — the field stays, results and all.
352
- useEffect(() => {
353
- if (!isSearchOpen) {return undefined;}
354
- const sub = Keyboard.addListener('keyboardDidHide', restoreHeader);
355
- return () => sub.remove();
356
- }, [isSearchOpen]); // eslint-disable-line react-hooks/exhaustive-deps
357
-
358
- const heroActions: HeroAction[] = useMemo(
359
- () => [
360
240
  {
361
- key: 'search',
362
- label: t('action.search'),
363
- icon: (color: string) => <SearchIcon color={color} />,
364
- onPress: openMemberSearch,
365
- },
366
- {
367
- key: 'leave',
368
- label: t('action.leave'),
369
- icon: (color: string) => <LeaveIcon color={color} />,
370
- onPress: handleLeave,
241
+ label: 'Unban',
242
+ icon: null,
243
+ onClick: () => {
244
+ dispatch(setActiveModal(MODAL_TYPES.SETTINGS));
245
+ console.log('Settings clicked');
246
+ },
371
247
  },
372
248
  {
373
- key: 'report',
374
- label: t('action.report'),
375
- icon: (color: string) => <ReportIcon color={color} />,
376
- onPress: () => setIsReportOpen(true),
249
+ label: 'Delete',
250
+ icon: null,
251
+ onClick: (e: any) => {
252
+ e?.preventDefault();
253
+ handleDeleteUser(userId);
254
+ },
377
255
  },
378
256
  ],
379
- [t, activeRoom?.jid] // eslint-disable-line react-hooks/exhaustive-deps
257
+ []
380
258
  );
381
259
 
382
- // "…" menu. Edit is the chat picture — the only chat detail this SDK can
383
- // actually change (there is no update-chat endpoint for title/description),
384
- // so it is only offered when the picture is editable.
385
- const menuItems: ProfileMenuItem[] = useMemo(() => {
386
- const items: ProfileMenuItem[] = [];
387
- if (canEditIcon) {
388
- items.push({
389
- key: 'edit',
390
- label: t('action.edit'),
391
- icon: <EditIcon color="#141414" width={18} height={18} />,
392
- onPress: onUpload,
393
- });
394
- if (hasIcon) {
395
- items.push({
396
- key: 'remove-photo',
397
- label: t('modal.chatProfile.removePhoto'),
398
- icon: <DeleteIcon width={18} height={18} />,
399
- onPress: onRemoveIcon,
400
- });
401
- }
402
- }
403
- // The hero's Search button is off-screen once collapsed, so the menu
404
- // carries it — the design's collapsed menu does the same.
405
- if (isCollapsed) {
406
- items.push({
407
- key: 'search',
408
- label: t('action.search'),
409
- icon: <SearchIcon color="#141414" width={18} height={18} />,
410
- onPress: openMemberSearch,
411
- });
412
- }
413
- items.push({
414
- key: 'report',
415
- label: t('action.report'),
416
- icon: <ReportIcon color="#141414" width={18} height={18} />,
417
- onPress: () => setIsReportOpen(true),
418
- });
419
- if (canDeleteChat) {
420
- items.push({
421
- key: 'delete-and-leave',
422
- label: t('action.deleteAndLeave'),
423
- icon: <DeleteIcon width={18} height={18} />,
424
- destructive: true,
425
- onPress: () => setIsDeleteOpen(true),
426
- });
260
+ useEffect(() => {
261
+ if (!activeRoom) {
262
+ dispatch(setActiveModal(undefined));
427
263
  }
428
- return items;
429
- }, [canEditIcon, canDeleteChat, hasIcon, isCollapsed, t]); // eslint-disable-line react-hooks/exhaustive-deps
264
+ }, [activeRoom, dispatch]);
430
265
 
431
266
  if (!activeRoom) {
432
267
  return null;
433
268
  }
434
269
 
435
- const title = activeRoom.title || activeRoom.name;
436
- const memberCount = activeRoom.usersCnt ?? 0;
437
- const subtitle = t(
438
- memberCount === 1
439
- ? 'modal.chatProfile.memberCountSingular'
440
- : 'modal.chatProfile.memberCountPlural',
441
- { count: memberCount }
442
- );
443
- const heroImage = appendFileToken(activeRoom.icon, fileToken) || null;
444
- // A single flat colour behind the initials — the config's avatar colour
445
- // when set, otherwise the primary. (The old per-name hash colour is what
446
- // made the header read as two different greens next to the members' own
447
- // avatars.)
448
- const heroColor = config?.colors?.avatar || getIconColor(config);
449
- const members = activeRoom.roomMembers ?? [];
450
- const query = memberQuery.trim().toLowerCase();
451
- const visibleMembers = query
452
- ? members.filter((user) =>
453
- `${user.firstName ?? ''} ${user.lastName ?? ''}`
454
- .toLowerCase()
455
- .includes(query)
456
- )
457
- : members;
458
-
459
270
  return (
460
- <ModalContainerFullScreen style={styles.screen}>
461
- <Animated.ScrollView
462
- ref={scrollRef}
463
- style={styles.scroll}
464
- // The collapsed state has to be reachable even when the member list
465
- // is short: without this the content was shorter than the viewport,
466
- // so the scroll had nowhere to go and simply bounced back.
467
- contentContainerStyle={[
468
- styles.scrollContent,
469
- viewportHeight > 0 && {
470
- minHeight: viewportHeight + collapseDistance,
471
- },
472
- ]}
473
- onLayout={(e) => setViewportHeight(e.nativeEvent.layout.height)}
474
- showsVerticalScrollIndicator={false}
475
- keyboardShouldPersistTaps="handled"
476
- scrollEventThrottle={16}
477
- onScroll={Animated.event(
478
- [{ nativeEvent: { contentOffset: { y: scrollY } } }],
479
- {
480
- useNativeDriver: true,
481
- listener: (e: any) => {
482
- const y = e?.nativeEvent?.contentOffset?.y ?? 0;
483
- setIsCollapsed(y >= collapseDistance - 8);
484
- },
485
- }
486
- )}
487
- >
488
- <ProfileHero
489
- title={title}
490
- subtitle={subtitle}
491
- imageUri={heroImage}
492
- fallbackColor={heroColor}
493
- initials={chatInitials(title)}
494
- scrollY={scrollY}
495
- actions={heroActions}
496
- titleStyle={chatTextStyle(config?.typography?.profile?.title)}
497
- subtitleStyle={getElementFont(config, 'profileStatus')}
498
- />
499
-
500
- <View style={styles.body}>
501
- {!config?.disableChatInfo?.disableDescription && (
502
- <View style={styles.card}>
503
- <Text style={[styles.cardLabel, getElementFont(config, 'profileSectionLabel')]}>
504
- {t('modal.chatProfile.description')}
505
- </Text>
506
- <Text style={styles.cardValue}>{activeRoom.description || '—'}</Text>
507
- </View>
508
- )}
509
-
510
- {!config?.disableChatInfo?.disableType && (
511
- <View style={styles.card}>
512
- <Text style={[styles.cardLabel, getElementFont(config, 'profileSectionLabel')]}>
513
- {t('modal.chatProfile.chatType')}
514
- </Text>
515
- <Text style={styles.cardValue}>{activeRoom.type || '—'}</Text>
516
- </View>
517
- )}
518
-
519
- {!config?.disableChatInfo?.hideMembers && (
520
- <View style={styles.card}>
521
- {canAddMembers && (
522
- <SelectUsersModal
523
- trigger={(open) => (
524
- <TouchableOpacity
525
- testID="chat-profile-add-members"
526
- activeOpacity={0.7}
527
- style={styles.addMembersRow}
528
- onPress={open}
529
- >
530
- <AddNewIcon color={getIconColor(config)} />
531
- <Text style={styles.addMembersLabel}>
532
- {t('modal.chatProfile.addMembers')}
533
- </Text>
534
- </TouchableOpacity>
535
- )}
271
+ <ModalContainerFullScreen style={{ position: 'relative' }}>
272
+ <ModalHeaderComponent
273
+ handleCloseModal={handleCloseModal}
274
+ headerTitle={'Chat Profile'}
275
+ titleStyle={chatTextStyle(config?.typography?.profile?.screenTitle)}
276
+ rightMenu={
277
+ <>
278
+ {activeRoom?.type === 'public' && (
279
+ <Button EndIcon={<QrIcon />} onPress={() => setVisible(true)} />
280
+ )}
281
+ {activeRoom.role === 'moderator' &&
282
+ activeRoom.type !== 'private' && (
283
+ <DropdownMenu
284
+ position="right"
285
+ options={chatMenuOptions}
286
+ openButton={
287
+ <Button
288
+ style={{ padding: 8, height: 40 }}
289
+ EndIcon={<MoreIcon />}
290
+ unstyled
291
+ />
292
+ }
536
293
  />
537
294
  )}
538
-
539
- <Text
540
- style={[
541
- styles.cardLabel,
542
- getElementFont(config, 'profileSectionLabel'),
543
- ]}
544
- >
545
- {t('modal.chatProfile.membersLabel', { count: memberCount })}
546
- </Text>
547
-
548
- {isSearchOpen && (
549
- <View style={styles.searchRow}>
550
- <SearchIcon color="#8C8C8C" width={18} height={18} />
551
- <TextInput
552
- testID="chat-profile-member-search"
553
- ref={searchInputRef}
554
- style={styles.searchInput}
555
- value={memberQuery}
556
- onChangeText={setMemberQuery}
557
- placeholder={t('search.members')}
558
- placeholderTextColor="#8C8C8C"
559
- autoCorrect={false}
560
- returnKeyType="search"
561
- />
562
- <TouchableOpacity
563
- testID="chat-profile-search-close"
564
- activeOpacity={0.7}
565
- hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
566
- onPress={closeMemberSearch}
295
+ </>
296
+ }
297
+ />
298
+ <ScrollView
299
+ style={{ width: '100%', flex: 1 }}
300
+ contentContainerStyle={{ flexGrow: 1 }}
301
+ showsVerticalScrollIndicator={true}
302
+ >
303
+ <CenterContainer>
304
+ <ProfileImagePlaceholder
305
+ name={activeRoom.title || activeRoom.name}
306
+ icon={appendFileToken(activeRoom.icon, fileToken)}
307
+ // Two gates control whether the icon is editable:
308
+ // 1. role — only non-participants could edit before.
309
+ // 2. NEW: `disableChatInfo.disableIconEdit` — hard kill from
310
+ // config so a consumer can make the icon read-only for
311
+ // everyone (e.g. branded rooms, patient-facing apps).
312
+ // Both must allow it for the picker/remove affordances to show.
313
+ upload={{
314
+ onUpload,
315
+ active:
316
+ !config?.disableChatInfo?.disableIconEdit &&
317
+ activeRoom?.role !== 'participant',
318
+ }}
319
+ remove={{
320
+ enabled: !config?.disableChatInfo?.disableIconEdit,
321
+ onRemoveClick,
322
+ }}
323
+ role={activeRoom?.role}
324
+ size={128}
325
+ />
326
+ <UserInfo>
327
+ <UserName
328
+ fontSize={config?.typography?.profile?.title?.fontSize}
329
+ fontWeight={config?.typography?.profile?.title?.fontWeight as any}
330
+ >
331
+ {activeRoom.title || activeRoom.name}
332
+ </UserName>
333
+ <UserStatus style={getElementFont(config, 'profileStatus')}>
334
+ {activeRoom.usersCnt}{' '}
335
+ {activeRoom.usersCnt > 1 ? 'members' : 'member'}
336
+ </UserStatus>
337
+ </UserInfo>
338
+ {activeRoom.role === 'moderator' && activeRoom.type === 'group' && (
339
+ <>
340
+ {/* <AddMembersModal /> */}
341
+ <SelectUsersModal />
342
+ </>
343
+ )}
344
+ {!config?.disableChatInfo?.disableDescription && (
345
+ <BorderedContainer>
346
+ <LabelData style={getElementFont(config, 'profileSectionLabel')}>
347
+ Description
348
+ </LabelData>
349
+ <Label>{activeRoom?.description || '—'}</Label>
350
+ </BorderedContainer>
351
+ )}
352
+ {!config?.disableChatInfo?.disableType && (
353
+ <BorderedContainer>
354
+ <LabelData style={getElementFont(config, 'profileSectionLabel')}>
355
+ Chat type
356
+ </LabelData>
357
+ <Label>{activeRoom.type || '—'}</Label>
358
+ </BorderedContainer>
359
+ )}
360
+ {/* <BorderedContainer
361
+ style={{
362
+ justifyContent: 'space-between',
363
+ flexDirection: 'row',
364
+ alignItems: 'center',
365
+ }}
366
+ >
367
+ <Label>Notifications</Label>
368
+ <Label>
369
+ <Switch
370
+ onToggle={function (isOn: boolean): void {
371
+ throw new Error('Function not implemented.');
372
+ }}
373
+ bgColor={config?.colors?.primary}
374
+ />
375
+ </Label>
376
+ </BorderedContainer> */}
377
+ {!config?.disableChatInfo?.hideMembers && (
378
+ <BorderedContainer style={{ paddingHorizontal: 16, paddingVertical: 8 }}>
379
+ {loading ? (
380
+ <Loader />
381
+ ) : (activeRoom?.roomMembers?.length ?? 0) === 0 ? (
382
+ <Label style={{ opacity: 0.6, textAlign: 'center', paddingVertical: 8 }}>
383
+ Member list unavailable
384
+ </Label>
385
+ ) : (
386
+ <View>
387
+ {activeRoom?.roomMembers?.map((user, index) => (
388
+ <View
389
+ key={user.xmppUsername}
390
+ style={{
391
+ flexDirection: 'column',
392
+ alignItems: 'flex-start',
393
+ }}
394
+ >
395
+ <View
396
+ style={{
397
+ flexDirection: 'row',
398
+ justifyContent: 'flex-start',
399
+ paddingHorizontal: 8,
400
+ paddingVertical: 0,
401
+ alignItems: 'center',
402
+ width: '100%',
403
+ }}
567
404
  >
568
- <Text style={styles.searchClose}>×</Text>
569
- </TouchableOpacity>
570
- </View>
571
- )}
572
-
573
- {loading ? (
574
- <Loader />
575
- ) : visibleMembers.length === 0 ? (
576
- <Text testID="chat-profile-members-empty" style={styles.emptyMembers}>
577
- {members.length === 0
578
- ? t('modal.chatProfile.membersUnavailable')
579
- : t('search.noResults')}
580
- </Text>
581
- ) : (
582
- visibleMembers.map((user, index) => {
583
- const banned = user.ban_status === 'banned';
584
- const roleLabel =
585
- user.role && user.role !== 'none' && user.role !== 'participant'
586
- ? user.role
587
- : null;
588
- return (
589
- <View
590
- key={user.xmppUsername}
591
- style={[styles.memberRow, index > 0 && styles.memberDivider]}
405
+ <Pressable
406
+ style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-start', gap: 16 }}
407
+ // `disableChatInfo.disableMemberTap` blocks the
408
+ // tap entirely so the user-profile popup never
409
+ // opens. `disableMemberProfileActions` only hid
410
+ // the action buttons INSIDE that popup, leaving
411
+ // the popup itself to open on tap — this gate
412
+ // closes the door. Customer-reported #16.
413
+ onPress={
414
+ config?.disableChatInfo?.disableMemberTap
415
+ ? undefined
416
+ : () => handleUserAvatarClick(user)
417
+ }
418
+ disabled={!!config?.disableChatInfo?.disableMemberTap}
592
419
  >
593
- <Pressable
594
- style={styles.memberMain}
595
- // `disableChatInfo.disableMemberTap` blocks the tap
596
- // entirely so the user-profile popup never opens.
597
- // `disableMemberProfileActions` only hid the action
598
- // buttons INSIDE that popup, leaving the popup itself
599
- // to open on tap — this gate closes the door.
600
- // Customer-reported #16.
601
- onPress={
602
- config?.disableChatInfo?.disableMemberTap
603
- ? undefined
604
- : () => handleUserAvatarClick(user)
605
- }
606
- disabled={!!config?.disableChatInfo?.disableMemberTap}
420
+ <ProfileImagePlaceholder
421
+ name={`${user.firstName} ${user.lastName}`}
422
+ size={40}
423
+ />
424
+ <View
425
+ style={{
426
+ flexDirection: 'column',
427
+ gap: 2,
428
+ alignItems: 'flex-start',
429
+ justifyContent: 'center',
430
+ }}
607
431
  >
608
- <ProfileImagePlaceholder
609
- name={`${user.firstName} ${user.lastName}`}
610
- size={40}
611
- />
612
- <View style={styles.memberText}>
613
- <Text
614
- numberOfLines={1}
615
- style={[
616
- styles.memberName,
617
- chatTextStyle(config?.typography?.profile?.memberName),
618
- ]}
619
- >
620
- {user.firstName} {user.lastName}
621
- </Text>
622
- {!!user.last_active && (
623
- <Text
624
- numberOfLines={1}
625
- style={[
626
- styles.memberStatus,
627
- getElementFont(config, 'profileSectionLabel'),
628
- ]}
629
- >
630
- {new Date(user.last_active * 1000).toLocaleString()}
631
- </Text>
632
- )}
633
- </View>
634
- </Pressable>
635
-
636
- {(banned || roleLabel) && (
637
- <Text
638
- style={[styles.memberRole, banned && styles.memberBanned]}
432
+ <Label
433
+ style={[
434
+ { fontSize: 16, fontWeight: 600 },
435
+ chatTextStyle(config?.typography?.profile?.memberName),
436
+ ]}
639
437
  >
640
- {banned ? t('status.banned') : roleLabel}
641
- </Text>
642
- )}
643
-
644
- {isModerator &&
645
- activeRoom.type !== 'private' &&
646
- stateUser.xmppUsername !== user.xmppUsername && (
647
- <TouchableOpacity
648
- testID={`chat-profile-remove-${user.xmppUsername}`}
649
- activeOpacity={0.7}
650
- hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
651
- style={styles.memberRemove}
652
- onPress={() => confirmRemoveMember(user)}
653
- >
654
- <DeleteIcon width={20} height={20} />
655
- </TouchableOpacity>
438
+ {user.firstName} {user.lastName}
439
+ </Label>
440
+ {user.last_active && (
441
+ <LabelData style={getElementFont(config, 'profileSectionLabel')}>
442
+ {new Date(user.last_active * 1000).toLocaleString()}
443
+ </LabelData>
656
444
  )}
657
- </View>
658
- );
659
- })
660
- )}
445
+ </View>
446
+ </Pressable>
447
+ {user.role && user.role !== 'none' && (
448
+ <Text
449
+ style={{
450
+ backgroundColor:
451
+ user.ban_status !== 'banned' ? '#F3F6FC' : '#FFEBEE',
452
+ color:
453
+ user.ban_status !== 'banned' ? '#0052CD' : '#F44336',
454
+ padding: 5,
455
+ borderRadius: 16,
456
+ fontSize: 12,
457
+ }}
458
+ >
459
+ {user.role}
460
+ </Text>
461
+ )}
462
+ {stateUser.xmppUsername !== user.xmppUsername &&
463
+ activeRoom.role === 'moderator' &&
464
+ activeRoom.type !== 'private' && (
465
+ <DropdownMenu
466
+ options={menuOptions(user.xmppUsername) as MenuOption[]}
467
+ openButton={
468
+ <Button
469
+ onPress={() => {}}
470
+ >
471
+ <Text>More Options</Text>
472
+ </Button>
473
+ }
474
+ onClose={() => console.log('Dropdown closed')}
475
+ />
476
+ )}
477
+ </View>
478
+ {index < (activeRoom?.roomMembers?.length || 0) - 1 && <Divider />}
479
+ </View>
480
+ ))}
661
481
  </View>
662
482
  )}
663
- </View>
664
- </Animated.ScrollView>
665
-
666
- <ProfileTopBar
667
- title={title}
668
- subtitle={subtitle}
669
- imageUri={heroImage}
670
- fallbackColor={heroColor}
671
- initials={chatInitials(title)}
672
- scrollY={scrollY}
673
- onBack={handleCloseModal}
674
- titleStyle={chatTextStyle(config?.typography?.profile?.screenTitle)}
675
- menu={<ProfileMenu items={menuItems} />}
676
- />
483
+ </BorderedContainer>
484
+ )}
485
+ </CenterContainer>
486
+ </ScrollView>
677
487
 
678
488
  <DeleteChatModal
679
- isModalOpen={isDeleteOpen}
680
- setIsModalOpen={setIsDeleteOpen}
681
- />
682
- <ReportChatModal
683
- visible={isReportOpen}
684
- onClose={() => setIsReportOpen(false)}
489
+ isModalOpen={isModalOpen}
490
+ setIsModalOpen={setIsModalOpen}
685
491
  />
686
492
  </ModalContainerFullScreen>
687
493
  );
688
494
  };
689
495
 
690
- const styles = StyleSheet.create({
691
- screen: {
692
- position: 'relative',
693
- backgroundColor: '#F2F3F5',
694
- },
695
- scroll: {
696
- width: '100%',
697
- flex: 1,
698
- },
699
- scrollContent: {
700
- paddingBottom: 32,
701
- },
702
- body: {
703
- padding: 12,
704
- gap: 12,
705
- },
706
- card: {
707
- backgroundColor: '#FFFFFF',
708
- borderRadius: 14,
709
- padding: 16,
710
- shadowColor: '#000',
711
- shadowOffset: { width: 0, height: 1 },
712
- shadowOpacity: 0.05,
713
- shadowRadius: 4,
714
- elevation: 1,
715
- },
716
- cardLabel: {
717
- color: '#8C8C8C',
718
- fontSize: 14,
719
- },
720
- cardValue: {
721
- color: '#141414',
722
- fontSize: 16,
723
- marginTop: 4,
724
- },
725
- addMembersRow: {
726
- flexDirection: 'row',
727
- alignItems: 'center',
728
- gap: 12,
729
- paddingBottom: 14,
730
- marginBottom: 10,
731
- borderBottomWidth: StyleSheet.hairlineWidth,
732
- borderBottomColor: '#EFEFF2',
733
- },
734
- addMembersLabel: {
735
- fontSize: 16,
736
- fontWeight: '500',
737
- color: '#141414',
738
- },
739
- searchRow: {
740
- flexDirection: 'row',
741
- alignItems: 'center',
742
- gap: 8,
743
- marginTop: 10,
744
- paddingHorizontal: 12,
745
- height: 40,
746
- borderRadius: 12,
747
- backgroundColor: '#F2F3F5',
748
- },
749
- searchInput: {
750
- flex: 1,
751
- fontSize: 15,
752
- color: '#141414',
753
- padding: 0,
754
- },
755
- searchClose: {
756
- fontSize: 22,
757
- lineHeight: 24,
758
- color: '#8C8C8C',
759
- },
760
- emptyMembers: {
761
- opacity: 0.6,
762
- textAlign: 'center',
763
- paddingVertical: 8,
764
- color: '#141414',
765
- },
766
- memberRow: {
767
- flexDirection: 'row',
768
- alignItems: 'center',
769
- paddingVertical: 10,
770
- },
771
- memberDivider: {
772
- borderTopWidth: StyleSheet.hairlineWidth,
773
- borderTopColor: '#EFEFF2',
774
- },
775
- memberMain: {
776
- flex: 1,
777
- flexDirection: 'row',
778
- alignItems: 'center',
779
- gap: 12,
780
- },
781
- memberText: {
782
- flex: 1,
783
- },
784
- memberName: {
785
- fontSize: 16,
786
- fontWeight: '600',
787
- color: '#141414',
788
- },
789
- memberStatus: {
790
- fontSize: 13,
791
- color: '#8C8C8C',
792
- marginTop: 2,
793
- },
794
- memberRole: {
795
- fontSize: 13,
796
- color: '#8C8C8C',
797
- marginLeft: 8,
798
- },
799
- memberBanned: {
800
- color: '#E53935',
801
- },
802
- memberRemove: {
803
- marginLeft: 12,
804
- },
805
- menuButton: {
806
- width: 40,
807
- height: 40,
808
- borderRadius: 20,
809
- backgroundColor: 'rgba(0,0,0,0.28)',
810
- alignItems: 'center',
811
- justifyContent: 'center',
812
- },
813
- });
814
-
815
496
  export default ChatProfileModal;