@ethora/chat-component-rn 26.8.7 → 26.8.9

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 +16 -0
  2. package/README.md +27 -4
  3. package/lib/commonjs/components/Header/HeaderRoomList.js +34 -6
  4. package/lib/commonjs/components/Header/HeaderRoomList.js.map +1 -1
  5. package/lib/commonjs/components/MainComponents/ChatHeader.js +15 -1
  6. package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
  7. package/lib/commonjs/components/MainComponents/ChatWrapper.js +5 -3
  8. package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
  9. package/lib/commonjs/components/MainComponents/ReduxWrapper.js +8 -0
  10. package/lib/commonjs/components/MainComponents/ReduxWrapper.js.map +1 -1
  11. package/lib/commonjs/components/MainComponents/RoomList.js +63 -11
  12. package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
  13. package/lib/commonjs/components/Menu/HeaderRoomListMenu.js +26 -13
  14. package/lib/commonjs/components/Menu/HeaderRoomListMenu.js.map +1 -1
  15. package/lib/commonjs/components/MenuRoom/MenuRoom.js +5 -3
  16. package/lib/commonjs/components/MenuRoom/MenuRoom.js.map +1 -1
  17. package/lib/commonjs/components/MessageBubble/Message.js +3 -3
  18. package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
  19. package/lib/commonjs/components/MessageBubble/MessageInteractions.js +5 -3
  20. package/lib/commonjs/components/MessageBubble/MessageInteractions.js.map +1 -1
  21. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +1 -1
  22. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  23. package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js +5 -4
  24. package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -1
  25. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +7 -5
  26. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  27. package/lib/commonjs/components/Modals/Modal/Modal.js +33 -11
  28. package/lib/commonjs/components/Modals/Modal/Modal.js.map +1 -1
  29. package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js +8 -8
  30. package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
  31. package/lib/commonjs/components/Modals/SettingsModals/ChangePassword/ChangePasswordModal.js +279 -0
  32. package/lib/commonjs/components/Modals/SettingsModals/ChangePassword/ChangePasswordModal.js.map +1 -0
  33. package/lib/commonjs/components/Modals/SettingsModals/ManageDataModal/ManageDataModal.js +10 -8
  34. package/lib/commonjs/components/Modals/SettingsModals/ManageDataModal/ManageDataModal.js.map +1 -1
  35. package/lib/commonjs/components/Modals/SettingsModals/Visibility/VisibilityModal.js +13 -11
  36. package/lib/commonjs/components/Modals/SettingsModals/Visibility/VisibilityModal.js.map +1 -1
  37. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +22 -38
  38. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  39. package/lib/commonjs/components/Modals/UserSettingsModal/LanguageCard.js +121 -0
  40. package/lib/commonjs/components/Modals/UserSettingsModal/LanguageCard.js.map +1 -0
  41. package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js +11 -6
  42. package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
  43. package/lib/commonjs/components/RoomComponents/SwipeableRoomRow.js +133 -0
  44. package/lib/commonjs/components/RoomComponents/SwipeableRoomRow.js.map +1 -0
  45. package/lib/commonjs/components/Thread/ThreadWrapper.js +4 -2
  46. package/lib/commonjs/components/Thread/ThreadWrapper.js.map +1 -1
  47. package/lib/commonjs/context/xmppProvider.js +15 -3
  48. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  49. package/lib/commonjs/e2ee/stanza.js +1 -1
  50. package/lib/commonjs/e2ee/stanza.js.map +1 -1
  51. package/lib/commonjs/helpers/constants/MODAL_COMPONENTS.js +2 -0
  52. package/lib/commonjs/helpers/constants/MODAL_COMPONENTS.js.map +1 -1
  53. package/lib/commonjs/helpers/constants/MODAL_TYPES.js +1 -0
  54. package/lib/commonjs/helpers/constants/MODAL_TYPES.js.map +1 -1
  55. package/lib/commonjs/helpers/preferencesStorage.js.map +1 -1
  56. package/lib/commonjs/hooks/useChatSettingState.js +4 -0
  57. package/lib/commonjs/hooks/useChatSettingState.js.map +1 -1
  58. package/lib/commonjs/hooks/useChatWrapperInit.js +4 -0
  59. package/lib/commonjs/hooks/useChatWrapperInit.js.map +1 -1
  60. package/lib/commonjs/hooks/useConnectionLabel.js +29 -0
  61. package/lib/commonjs/hooks/useConnectionLabel.js.map +1 -0
  62. package/lib/commonjs/i18n/strings.js +199 -1
  63. package/lib/commonjs/i18n/strings.js.map +1 -1
  64. package/lib/commonjs/i18n/useT.js +8 -4
  65. package/lib/commonjs/i18n/useT.js.map +1 -1
  66. package/lib/commonjs/networking/api-requests/user.api.js +13 -0
  67. package/lib/commonjs/networking/api-requests/user.api.js.map +1 -1
  68. package/lib/commonjs/networking/stanzaHandlers.js +1 -1
  69. package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
  70. package/lib/commonjs/networking/xmppClient.js +29 -1
  71. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  72. package/lib/commonjs/roomStore/chatSettingsSlice.js +12 -2
  73. package/lib/commonjs/roomStore/chatSettingsSlice.js.map +1 -1
  74. package/lib/commonjs/services/languageSettings.js +177 -0
  75. package/lib/commonjs/services/languageSettings.js.map +1 -0
  76. package/lib/commonjs/version.js +1 -1
  77. package/lib/module/components/Header/HeaderRoomList.js +34 -6
  78. package/lib/module/components/Header/HeaderRoomList.js.map +1 -1
  79. package/lib/module/components/MainComponents/ChatHeader.js +15 -1
  80. package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
  81. package/lib/module/components/MainComponents/ChatWrapper.js +5 -3
  82. package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
  83. package/lib/module/components/MainComponents/ReduxWrapper.js +9 -1
  84. package/lib/module/components/MainComponents/ReduxWrapper.js.map +1 -1
  85. package/lib/module/components/MainComponents/RoomList.js +64 -12
  86. package/lib/module/components/MainComponents/RoomList.js.map +1 -1
  87. package/lib/module/components/Menu/HeaderRoomListMenu.js +26 -13
  88. package/lib/module/components/Menu/HeaderRoomListMenu.js.map +1 -1
  89. package/lib/module/components/MenuRoom/MenuRoom.js +5 -3
  90. package/lib/module/components/MenuRoom/MenuRoom.js.map +1 -1
  91. package/lib/module/components/MessageBubble/Message.js +3 -3
  92. package/lib/module/components/MessageBubble/Message.js.map +1 -1
  93. package/lib/module/components/MessageBubble/MessageInteractions.js +5 -3
  94. package/lib/module/components/MessageBubble/MessageInteractions.js.map +1 -1
  95. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +1 -1
  96. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  97. package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js +5 -4
  98. package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -1
  99. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +7 -5
  100. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  101. package/lib/module/components/Modals/Modal/Modal.js +33 -11
  102. package/lib/module/components/Modals/Modal/Modal.js.map +1 -1
  103. package/lib/module/components/Modals/NewChatModal/NewChatModal.js +8 -8
  104. package/lib/module/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
  105. package/lib/module/components/Modals/SettingsModals/ChangePassword/ChangePasswordModal.js +274 -0
  106. package/lib/module/components/Modals/SettingsModals/ChangePassword/ChangePasswordModal.js.map +1 -0
  107. package/lib/module/components/Modals/SettingsModals/ManageDataModal/ManageDataModal.js +10 -8
  108. package/lib/module/components/Modals/SettingsModals/ManageDataModal/ManageDataModal.js.map +1 -1
  109. package/lib/module/components/Modals/SettingsModals/Visibility/VisibilityModal.js +13 -11
  110. package/lib/module/components/Modals/SettingsModals/Visibility/VisibilityModal.js.map +1 -1
  111. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +24 -40
  112. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  113. package/lib/module/components/Modals/UserSettingsModal/LanguageCard.js +116 -0
  114. package/lib/module/components/Modals/UserSettingsModal/LanguageCard.js.map +1 -0
  115. package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js +10 -5
  116. package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
  117. package/lib/module/components/RoomComponents/SwipeableRoomRow.js +126 -0
  118. package/lib/module/components/RoomComponents/SwipeableRoomRow.js.map +1 -0
  119. package/lib/module/components/Thread/ThreadWrapper.js +4 -2
  120. package/lib/module/components/Thread/ThreadWrapper.js.map +1 -1
  121. package/lib/module/context/xmppProvider.js +16 -4
  122. package/lib/module/context/xmppProvider.js.map +1 -1
  123. package/lib/module/e2ee/stanza.js +1 -1
  124. package/lib/module/e2ee/stanza.js.map +1 -1
  125. package/lib/module/helpers/constants/MODAL_COMPONENTS.js +2 -0
  126. package/lib/module/helpers/constants/MODAL_COMPONENTS.js.map +1 -1
  127. package/lib/module/helpers/constants/MODAL_TYPES.js +1 -0
  128. package/lib/module/helpers/constants/MODAL_TYPES.js.map +1 -1
  129. package/lib/module/helpers/preferencesStorage.js.map +1 -1
  130. package/lib/module/hooks/useChatSettingState.js +4 -0
  131. package/lib/module/hooks/useChatSettingState.js.map +1 -1
  132. package/lib/module/hooks/useChatWrapperInit.js +4 -0
  133. package/lib/module/hooks/useChatWrapperInit.js.map +1 -1
  134. package/lib/module/hooks/useConnectionLabel.js +25 -0
  135. package/lib/module/hooks/useConnectionLabel.js.map +1 -0
  136. package/lib/module/i18n/strings.js +199 -1
  137. package/lib/module/i18n/strings.js.map +1 -1
  138. package/lib/module/i18n/useT.js +8 -4
  139. package/lib/module/i18n/useT.js.map +1 -1
  140. package/lib/module/networking/api-requests/user.api.js +12 -0
  141. package/lib/module/networking/api-requests/user.api.js.map +1 -1
  142. package/lib/module/networking/stanzaHandlers.js +1 -1
  143. package/lib/module/networking/stanzaHandlers.js.map +1 -1
  144. package/lib/module/networking/xmppClient.js +29 -1
  145. package/lib/module/networking/xmppClient.js.map +1 -1
  146. package/lib/module/roomStore/chatSettingsSlice.js +9 -1
  147. package/lib/module/roomStore/chatSettingsSlice.js.map +1 -1
  148. package/lib/module/services/languageSettings.js +164 -0
  149. package/lib/module/services/languageSettings.js.map +1 -0
  150. package/lib/module/version.js +1 -1
  151. package/lib/typescript/components/Header/HeaderRoomList.d.ts +1 -0
  152. package/lib/typescript/components/Header/HeaderRoomList.d.ts.map +1 -1
  153. package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
  154. package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
  155. package/lib/typescript/components/MainComponents/ReduxWrapper.d.ts.map +1 -1
  156. package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
  157. package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts +7 -1
  158. package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts.map +1 -1
  159. package/lib/typescript/components/MenuRoom/MenuRoom.d.ts.map +1 -1
  160. package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts.map +1 -1
  161. package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts +2 -0
  162. package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts.map +1 -1
  163. package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
  164. package/lib/typescript/components/Modals/Modal/Modal.d.ts.map +1 -1
  165. package/lib/typescript/components/Modals/SettingsModals/ChangePassword/ChangePasswordModal.d.ts +15 -0
  166. package/lib/typescript/components/Modals/SettingsModals/ChangePassword/ChangePasswordModal.d.ts.map +1 -0
  167. package/lib/typescript/components/Modals/SettingsModals/ManageDataModal/ManageDataModal.d.ts.map +1 -1
  168. package/lib/typescript/components/Modals/SettingsModals/Visibility/VisibilityModal.d.ts.map +1 -1
  169. package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
  170. package/lib/typescript/components/Modals/UserSettingsModal/LanguageCard.d.ts +14 -0
  171. package/lib/typescript/components/Modals/UserSettingsModal/LanguageCard.d.ts.map +1 -0
  172. package/lib/typescript/components/Modals/UserSettingsModal/UserSettingsModal.d.ts.map +1 -1
  173. package/lib/typescript/components/RoomComponents/SwipeableRoomRow.d.ts +19 -0
  174. package/lib/typescript/components/RoomComponents/SwipeableRoomRow.d.ts.map +1 -0
  175. package/lib/typescript/components/Thread/ThreadWrapper.d.ts.map +1 -1
  176. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  177. package/lib/typescript/helpers/constants/MODAL_COMPONENTS.d.ts.map +1 -1
  178. package/lib/typescript/helpers/constants/MODAL_TYPES.d.ts +1 -0
  179. package/lib/typescript/helpers/constants/MODAL_TYPES.d.ts.map +1 -1
  180. package/lib/typescript/helpers/preferencesStorage.d.ts +4 -0
  181. package/lib/typescript/helpers/preferencesStorage.d.ts.map +1 -1
  182. package/lib/typescript/hooks/useChatSettingState.d.ts +2 -0
  183. package/lib/typescript/hooks/useChatSettingState.d.ts.map +1 -1
  184. package/lib/typescript/hooks/useChatWrapperInit.d.ts.map +1 -1
  185. package/lib/typescript/hooks/useConnectionLabel.d.ts +8 -0
  186. package/lib/typescript/hooks/useConnectionLabel.d.ts.map +1 -0
  187. package/lib/typescript/i18n/strings.d.ts.map +1 -1
  188. package/lib/typescript/i18n/useT.d.ts.map +1 -1
  189. package/lib/typescript/networking/api-requests/user.api.d.ts +6 -0
  190. package/lib/typescript/networking/api-requests/user.api.d.ts.map +1 -1
  191. package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
  192. package/lib/typescript/networking/xmppClient.d.ts +11 -1
  193. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  194. package/lib/typescript/roomStore/chatSettingsSlice.d.ts +18 -1
  195. package/lib/typescript/roomStore/chatSettingsSlice.d.ts.map +1 -1
  196. package/lib/typescript/services/languageSettings.d.ts +29 -0
  197. package/lib/typescript/services/languageSettings.d.ts.map +1 -0
  198. package/lib/typescript/types/models/user.model.d.ts +4 -0
  199. package/lib/typescript/types/models/user.model.d.ts.map +1 -1
  200. package/lib/typescript/types/types.d.ts +23 -0
  201. package/lib/typescript/types/types.d.ts.map +1 -1
  202. package/lib/typescript/version.d.ts +1 -1
  203. package/package.json +1 -1
  204. package/src/components/Header/HeaderRoomList.tsx +31 -6
  205. package/src/components/MainComponents/ChatHeader.tsx +16 -1
  206. package/src/components/MainComponents/ChatWrapper.tsx +5 -3
  207. package/src/components/MainComponents/ReduxWrapper.tsx +6 -0
  208. package/src/components/MainComponents/RoomList.tsx +78 -12
  209. package/src/components/Menu/HeaderRoomListMenu.tsx +40 -13
  210. package/src/components/MenuRoom/MenuRoom.tsx +5 -3
  211. package/src/components/MessageBubble/Message.tsx +3 -3
  212. package/src/components/MessageBubble/MessageInteractions.tsx +5 -3
  213. package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +1 -1
  214. package/src/components/Modals/ChatProfileModal/ReportChatModal.tsx +6 -3
  215. package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +7 -5
  216. package/src/components/Modals/Modal/Modal.tsx +44 -16
  217. package/src/components/Modals/NewChatModal/NewChatModal.tsx +8 -8
  218. package/src/components/Modals/SettingsModals/ChangePassword/ChangePasswordModal.tsx +316 -0
  219. package/src/components/Modals/SettingsModals/ManageDataModal/ManageDataModal.tsx +10 -15
  220. package/src/components/Modals/SettingsModals/Visibility/VisibilityModal.tsx +13 -14
  221. package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +19 -40
  222. package/src/components/Modals/UserSettingsModal/LanguageCard.tsx +144 -0
  223. package/src/components/Modals/UserSettingsModal/UserSettingsModal.tsx +11 -4
  224. package/src/components/RoomComponents/SwipeableRoomRow.tsx +133 -0
  225. package/src/components/Thread/ThreadWrapper.tsx +4 -2
  226. package/src/context/xmppProvider.tsx +21 -4
  227. package/src/e2ee/stanza.ts +1 -1
  228. package/src/helpers/constants/MODAL_COMPONENTS.tsx +2 -0
  229. package/src/helpers/constants/MODAL_TYPES.ts +1 -0
  230. package/src/helpers/preferencesStorage.ts +4 -0
  231. package/src/hooks/useChatSettingState.tsx +8 -0
  232. package/src/hooks/useChatWrapperInit.ts +4 -0
  233. package/src/hooks/useConnectionLabel.ts +16 -0
  234. package/src/i18n/strings.ts +199 -1
  235. package/src/i18n/useT.ts +6 -4
  236. package/src/networking/api-requests/user.api.ts +9 -0
  237. package/src/networking/stanzaHandlers.ts +1 -0
  238. package/src/networking/xmppClient.ts +33 -1
  239. package/src/roomStore/chatSettingsSlice.ts +30 -0
  240. package/src/services/languageSettings.ts +143 -0
  241. package/src/types/models/user.model.ts +4 -0
  242. package/src/types/types.ts +23 -0
  243. package/src/version.ts +1 -1
@@ -0,0 +1,316 @@
1
+ import React, { useCallback, useMemo, useState } from 'react';
2
+ import {
3
+ ActivityIndicator,
4
+ KeyboardAvoidingView,
5
+ Platform,
6
+ ScrollView,
7
+ StyleSheet,
8
+ Text,
9
+ TextInput,
10
+ TouchableOpacity,
11
+ View,
12
+ } from 'react-native';
13
+ import ModalHeaderComponent from '../../ModalHeaderComponent';
14
+ import { ModalContainerFullScreen } from '../../styledModalComponents';
15
+ import { useTheme } from '../../../../hooks/useTheme';
16
+ import type { ChatTheme } from '../../../../theme/theme';
17
+ import { useT } from '../../../../i18n/useT';
18
+ import { useToast } from '../../../../context/ToastContext';
19
+ import { useChatSettingState } from '../../../../hooks/useChatSettingState';
20
+ import { changePassword } from '../../../../networking/api-requests/user.api';
21
+ import { chatTextStyle } from '../../../../helpers/typography';
22
+
23
+ /** What the backend asks of a password at sign-up. */
24
+ export const MIN_PASSWORD_LENGTH = 8;
25
+
26
+ /** The reason a backend gave, or nothing - never an axios dump. */
27
+ const serverReason = (error: any): string => {
28
+ const data = error?.response?.data;
29
+ const text =
30
+ (typeof data === 'string' && data) ||
31
+ data?.message ||
32
+ data?.error ||
33
+ (Array.isArray(data?.errors) && data.errors.map((e: any) => e?.message || e).join(', ')) ||
34
+ '';
35
+ return typeof text === 'string' ? text.trim() : '';
36
+ };
37
+
38
+ interface FieldProps {
39
+ testID: string;
40
+ label: string;
41
+ value: string;
42
+ onChangeText: (value: string) => void;
43
+ error?: string;
44
+ editable: boolean;
45
+ newPassword?: boolean;
46
+ onSubmitEditing?: () => void;
47
+ styles: ReturnType<typeof createStyles>;
48
+ theme: ChatTheme;
49
+ }
50
+
51
+ /** One labelled password field: label above, error (if any) below. */
52
+ const Field: React.FC<FieldProps> = ({
53
+ testID,
54
+ label,
55
+ value,
56
+ onChangeText,
57
+ error,
58
+ editable,
59
+ newPassword,
60
+ onSubmitEditing,
61
+ styles,
62
+ theme,
63
+ }) => (
64
+ <View style={styles.field}>
65
+ <Text style={styles.fieldLabel}>{label}</Text>
66
+ <TextInput
67
+ testID={testID}
68
+ style={[styles.input, error ? styles.inputError : null]}
69
+ value={value}
70
+ onChangeText={onChangeText}
71
+ placeholder={label}
72
+ placeholderTextColor={theme.textMuted}
73
+ keyboardAppearance={theme.dark ? 'dark' : 'light'}
74
+ secureTextEntry
75
+ autoCapitalize="none"
76
+ autoCorrect={false}
77
+ textContentType={newPassword ? 'newPassword' : 'password'}
78
+ editable={editable}
79
+ returnKeyType={onSubmitEditing ? 'done' : 'next'}
80
+ onSubmitEditing={onSubmitEditing}
81
+ blurOnSubmit={!!onSubmitEditing}
82
+ />
83
+ {error ? <Text style={styles.fieldError}>{error}</Text> : null}
84
+ </View>
85
+ );
86
+
87
+ interface ChangePasswordModalProps {
88
+ handleCloseModal: () => void;
89
+ }
90
+
91
+ /**
92
+ * Change the account password: the current one, the new one twice. Nothing
93
+ * is sent until the form is complete and the two match; what the backend
94
+ * refuses is shown as it said it. Laid out like the Settings screen it is
95
+ * reached from: one card on the list ground.
96
+ */
97
+ const ChangePasswordModal: React.FC<ChangePasswordModalProps> = ({ handleCloseModal }) => {
98
+ const theme = useTheme();
99
+ const t = useT();
100
+ const { showToast } = useToast();
101
+ const { config } = useChatSettingState();
102
+ const styles = useMemo(() => createStyles(theme), [theme]);
103
+ const [current, setCurrent] = useState('');
104
+ const [next, setNext] = useState('');
105
+ const [again, setAgain] = useState('');
106
+ const [busy, setBusy] = useState(false);
107
+ const [error, setError] = useState('');
108
+
109
+ const mismatch = again.length > 0 && next !== again;
110
+ const tooShort = next.length > 0 && next.length < MIN_PASSWORD_LENGTH;
111
+ const sameAsCurrent = next.length > 0 && next === current;
112
+ const ready =
113
+ current.length > 0 &&
114
+ next.length >= MIN_PASSWORD_LENGTH &&
115
+ next === again &&
116
+ !sameAsCurrent &&
117
+ !busy;
118
+
119
+ const submit = useCallback(async () => {
120
+ if (!ready) {return;}
121
+ setBusy(true);
122
+ setError('');
123
+ try {
124
+ await changePassword(current, next);
125
+ showToast({
126
+ id: Date.now().toString(),
127
+ title: t('settings.password.title'),
128
+ message: t('settings.password.changed'),
129
+ type: 'success',
130
+ });
131
+ handleCloseModal();
132
+ } catch (err) {
133
+ const status = (err as any)?.response?.status;
134
+ setError(
135
+ serverReason(err) ||
136
+ (status === 400 || status === 401 || status === 403
137
+ ? t('settings.password.wrongCurrent')
138
+ : t('settings.password.failed'))
139
+ );
140
+ setBusy(false);
141
+ }
142
+ }, [current, handleCloseModal, next, ready, showToast, t]);
143
+
144
+ const newError = tooShort
145
+ ? t('settings.password.tooShort', { min: MIN_PASSWORD_LENGTH })
146
+ : sameAsCurrent
147
+ ? t('settings.password.sameAsCurrent')
148
+ : undefined;
149
+
150
+ return (
151
+ <ModalContainerFullScreen style={styles.screen}>
152
+ <ModalHeaderComponent
153
+ handleCloseModal={handleCloseModal}
154
+ headerTitle={t('settings.password.title')}
155
+ titleStyle={chatTextStyle(config?.typography?.profile?.screenTitle)}
156
+ />
157
+ <KeyboardAvoidingView
158
+ behavior={Platform.OS === 'ios' ? 'padding' : undefined}
159
+ style={styles.fill}
160
+ >
161
+ <ScrollView
162
+ style={styles.fill}
163
+ contentContainerStyle={styles.body}
164
+ keyboardShouldPersistTaps="handled"
165
+ >
166
+ <View style={styles.card} testID="settings-change-password">
167
+ <Field
168
+ testID="password-current"
169
+ label={t('settings.password.current')}
170
+ value={current}
171
+ onChangeText={setCurrent}
172
+ editable={!busy}
173
+ styles={styles}
174
+ theme={theme}
175
+ />
176
+ <Field
177
+ testID="password-new"
178
+ label={t('settings.password.new')}
179
+ value={next}
180
+ onChangeText={setNext}
181
+ error={newError}
182
+ editable={!busy}
183
+ newPassword
184
+ styles={styles}
185
+ theme={theme}
186
+ />
187
+ <Field
188
+ testID="password-again"
189
+ label={t('settings.password.again')}
190
+ value={again}
191
+ onChangeText={setAgain}
192
+ error={mismatch ? t('settings.password.mismatch') : undefined}
193
+ editable={!busy}
194
+ newPassword
195
+ onSubmitEditing={submit}
196
+ styles={styles}
197
+ theme={theme}
198
+ />
199
+ <Text style={styles.hint}>{t('settings.password.hint')}</Text>
200
+ </View>
201
+
202
+ {!!error && (
203
+ <Text testID="password-error" style={styles.error}>
204
+ {error}
205
+ </Text>
206
+ )}
207
+
208
+ <TouchableOpacity
209
+ testID="password-submit"
210
+ accessibilityRole="button"
211
+ accessibilityState={{ disabled: !ready }}
212
+ activeOpacity={0.8}
213
+ disabled={!ready}
214
+ onPress={submit}
215
+ style={[styles.button, !ready ? styles.buttonDisabled : null]}
216
+ >
217
+ {busy ? (
218
+ <ActivityIndicator color={theme.textOnPrimary} />
219
+ ) : (
220
+ <Text style={[styles.buttonText, !ready ? styles.buttonTextDisabled : null]}>
221
+ {t('settings.password.submit')}
222
+ </Text>
223
+ )}
224
+ </TouchableOpacity>
225
+ </ScrollView>
226
+ </KeyboardAvoidingView>
227
+ </ModalContainerFullScreen>
228
+ );
229
+ };
230
+
231
+ export default ChangePasswordModal;
232
+
233
+ const createStyles = (theme: ChatTheme) =>
234
+ StyleSheet.create({
235
+ screen: {
236
+ backgroundColor: theme.listBackground,
237
+ },
238
+ fill: {
239
+ flex: 1,
240
+ width: '100%',
241
+ },
242
+ body: {
243
+ padding: 12,
244
+ gap: 12,
245
+ paddingBottom: 32,
246
+ },
247
+ // Same surface as the Settings cards this screen is reached from.
248
+ card: {
249
+ backgroundColor: theme.surface,
250
+ borderRadius: 20,
251
+ paddingHorizontal: 20,
252
+ paddingVertical: 22,
253
+ gap: 18,
254
+ shadowColor: theme.shadow,
255
+ shadowOffset: { width: 0, height: 4 },
256
+ shadowOpacity: 0.06,
257
+ shadowRadius: 12,
258
+ elevation: 3,
259
+ },
260
+ field: {
261
+ gap: 8,
262
+ },
263
+ fieldLabel: {
264
+ fontSize: 14,
265
+ fontWeight: '500',
266
+ color: theme.textSecondary,
267
+ },
268
+ input: {
269
+ height: 48,
270
+ paddingHorizontal: 16,
271
+ borderRadius: 12,
272
+ borderWidth: 1,
273
+ borderColor: theme.border,
274
+ backgroundColor: theme.surfaceSecondary,
275
+ fontSize: 16,
276
+ color: theme.text,
277
+ },
278
+ inputError: {
279
+ borderColor: theme.danger,
280
+ },
281
+ fieldError: {
282
+ fontSize: 13,
283
+ lineHeight: 18,
284
+ color: theme.danger,
285
+ },
286
+ hint: {
287
+ fontSize: 13,
288
+ lineHeight: 18,
289
+ color: theme.textSecondary,
290
+ },
291
+ error: {
292
+ fontSize: 14,
293
+ lineHeight: 19,
294
+ paddingHorizontal: 8,
295
+ color: theme.danger,
296
+ },
297
+ button: {
298
+ minHeight: 48,
299
+ borderRadius: 14,
300
+ alignItems: 'center',
301
+ justifyContent: 'center',
302
+ paddingHorizontal: 20,
303
+ backgroundColor: theme.primary,
304
+ },
305
+ buttonDisabled: {
306
+ backgroundColor: theme.surfaceSecondary,
307
+ },
308
+ buttonText: {
309
+ fontSize: 16,
310
+ fontWeight: '600',
311
+ color: theme.textOnPrimary,
312
+ },
313
+ buttonTextDisabled: {
314
+ color: theme.textMuted,
315
+ },
316
+ });
@@ -21,6 +21,7 @@ import {
21
21
  } from '../SharedStyledComponents';
22
22
  import { View } from 'react-native';
23
23
  import { useTheme } from '../../../../hooks/useTheme';
24
+ import { useT } from '../../../../i18n/useT';
24
25
 
25
26
  interface ManageDataModalProps {
26
27
  handleCloseModal: any;
@@ -39,6 +40,7 @@ const ManageDataModal: React.FC<ManageDataModalProps> = ({
39
40
  }) => {
40
41
  const { config } = useSelector((state: RootState) => state.chatSettingStore);
41
42
  const theme = useTheme();
43
+ const t = useT();
42
44
 
43
45
  const handleDownloadClick = async () => {
44
46
  // const exportedData = await getExportMyData();
@@ -59,13 +61,13 @@ const ManageDataModal: React.FC<ManageDataModalProps> = ({
59
61
  <ModalContainerFullScreen>
60
62
  <ModalHeaderComponent
61
63
  handleCloseModal={handleCloseModal}
62
- headerTitle={'Manage Data'}
64
+ headerTitle={t('settings.manageData.title')}
63
65
  />
64
66
  <SharedSettingsCenterContainer>
65
67
  <SharedSettingsColumnContainer>
66
68
  <SharedSettingsSectionContainer>
67
69
  <SharedSettingsStyledLabel>
68
- Download your data
70
+ {t('settings.manageData.downloadLabel')}
69
71
  </SharedSettingsStyledLabel>
70
72
  <LabelData
71
73
  style={{
@@ -73,25 +75,23 @@ const ManageDataModal: React.FC<ManageDataModalProps> = ({
73
75
  textAlign: 'left',
74
76
  }}
75
77
  >
76
- You own your data. Tap the button below to download a copy of your
77
- data
78
+ {t('settings.manageData.downloadDescription')}
78
79
  </LabelData>
79
80
  </SharedSettingsSectionContainer>
80
81
  <SharedSettingsStyledButton
81
82
  borderColor={theme.primary}
82
83
  onPress={handleDownloadClick}
83
- text="Download your data"
84
+ text={t('settings.manageData.downloadLabel')}
84
85
  color={theme.primary}
85
86
  />
86
87
  </SharedSettingsColumnContainer>
87
88
  <SharedSettingsColumnContainer>
88
89
  <SharedSettingsSectionContainer>
89
90
  <SharedSettingsStyledLabel>
90
- Download your data
91
+ {t('settings.manageData.deleteLabel')}
91
92
  </SharedSettingsStyledLabel>
92
93
  <SharedSettingsLabelData>
93
- Use this only if you want to permanently delete your account &
94
- data from our system.
94
+ {t('settings.manageData.deleteDescription')}
95
95
  </SharedSettingsLabelData>
96
96
  </SharedSettingsSectionContainer>
97
97
  <SharedSettingsInfoPanel
@@ -101,17 +101,12 @@ const ManageDataModal: React.FC<ManageDataModalProps> = ({
101
101
  <InfoIcon color={theme.primary} />
102
102
  </View>
103
103
  <SharedSettingsInfoText>
104
- Due to the immutable nature of distributed ledger technology,
105
- network nodes operated by the community may still retain
106
- historical transactions generated by your account, however your
107
- personally identifiable information such as your name, e-mail,
108
- your key-value storage etc will be removed. Any of your digital
109
- assets will be lost.
104
+ {t('settings.manageData.deleteDisclosure')}
110
105
  </SharedSettingsInfoText>
111
106
  </SharedSettingsInfoPanel>
112
107
  <SharedSettingsStyledButton
113
108
  borderColor={theme.danger}
114
- text="Delete My Account"
109
+ text={t('action.deleteMyAccount')}
115
110
  color={theme.danger}
116
111
  />
117
112
  </SharedSettingsColumnContainer>
@@ -16,6 +16,7 @@ import {
16
16
  } from '../SharedStyledComponents';
17
17
  import { RadioInput } from './RadioInput';
18
18
  import { useTheme } from '../../../../hooks/useTheme';
19
+ import { useT } from '../../../../i18n/useT';
19
20
 
20
21
  interface VisibilityModalProps {
21
22
  handleCloseModal: any;
@@ -27,6 +28,7 @@ const VisibilityModal: React.FC<VisibilityModalProps> = ({
27
28
  const dispatch = useDispatch();
28
29
  const { user } = useSelector((state: RootState) => state.chatSettingStore);
29
30
  const theme = useTheme();
31
+ const t = useT();
30
32
 
31
33
  const doUpdateUser = (user: User) => dispatch(setUser(user));
32
34
  const [isProfileOpen, setIsProfileOpen] = useState(user?.isProfileOpen);
@@ -67,17 +69,17 @@ const VisibilityModal: React.FC<VisibilityModalProps> = ({
67
69
  <ModalContainerFullScreen>
68
70
  <ModalHeaderComponent
69
71
  handleCloseModal={handleCloseModal}
70
- headerTitle={'Visibility'}
72
+ headerTitle={t('settings.visibility.title')}
71
73
  />
72
74
  <SharedSettingsCenterContainer>
73
75
  <SharedSettingsColumnContainer>
74
76
  <SharedSettingsStyledLabel>
75
- Profile Visiblility
77
+ {t('settings.visibility.profileLabel')}
76
78
  </SharedSettingsStyledLabel>
77
79
  <RadioGroup>
78
80
  <RadioLabel>
79
81
  <RadioInput
80
- option={{ label: 'Open (default)', value: isProfileOpen }}
82
+ option={{ label: t('settings.visibility.open'), value: isProfileOpen }}
81
83
  radioColor={theme.primary}
82
84
  checked={isProfileOpen === true}
83
85
  onChange={() => setIsProfileOpen(true)}
@@ -85,50 +87,47 @@ const VisibilityModal: React.FC<VisibilityModalProps> = ({
85
87
  </RadioLabel>
86
88
 
87
89
  <SharedSettingsLabelData>
88
- Your profile can be viewed by anyone who follows your profile link
89
- or QR code.
90
+ {t('settings.visibility.openDescription')}
90
91
  </SharedSettingsLabelData>
91
92
  <RadioLabel>
92
93
  <RadioInput
93
- option={{ label: 'Restricted', value: isProfileOpen }}
94
+ option={{ label: t('settings.visibility.restricted'), value: isProfileOpen }}
94
95
  radioColor={theme.primary}
95
96
  checked={isProfileOpen === false}
96
97
  onChange={() => setIsProfileOpen(false)}
97
98
  />
98
99
  </RadioLabel>
99
100
  <SharedSettingsLabelData>
100
- Only users with your permission or temporary secure link can see
101
- your profile.
101
+ {t('settings.visibility.restrictedDescription')}
102
102
  </SharedSettingsLabelData>
103
103
  </RadioGroup>
104
104
  </SharedSettingsColumnContainer>
105
105
  <SharedSettingsColumnContainer>
106
106
  <SharedSettingsStyledLabel>
107
- Documents Visibility
107
+ {t('settings.visibility.documentsLabel')}
108
108
  </SharedSettingsStyledLabel>
109
109
  <RadioGroup>
110
110
  <RadioLabel>
111
111
  <RadioInput
112
- option={{ label: 'Full (default)', value: isAssetsOpen }}
112
+ option={{ label: t('settings.visibility.full'), value: isAssetsOpen }}
113
113
  radioColor={theme.primary}
114
114
  checked={isAssetsOpen === true}
115
115
  onChange={() => setIsAssetsOpen(true)}
116
116
  />
117
117
  </RadioLabel>
118
118
  <SharedSettingsLabelData>
119
- Show all Documents to those who can see your profile.
119
+ {t('settings.visibility.fullDescription')}
120
120
  </SharedSettingsLabelData>
121
121
  <RadioLabel>
122
122
  <RadioInput
123
- option={{ label: 'InViewidual', value: isAssetsOpen }}
123
+ option={{ label: t('settings.visibility.individual'), value: isAssetsOpen }}
124
124
  radioColor={theme.primary}
125
125
  checked={isAssetsOpen === false}
126
126
  onChange={() => setIsAssetsOpen(false)}
127
127
  />
128
128
  </RadioLabel>
129
129
  <SharedSettingsLabelData>
130
- You need to share each document inViewidually before others can
131
- see them.
130
+ {t('settings.visibility.individualDescription')}
132
131
  </SharedSettingsLabelData>
133
132
  </RadioGroup>
134
133
  </SharedSettingsColumnContainer>
@@ -16,7 +16,6 @@ import {
16
16
  ChatIcon,
17
17
  EditIcon,
18
18
  IconDoc,
19
- LeaveIcon,
20
19
  LockIcon,
21
20
  LogoutIcon,
22
21
  ProfileIcon,
@@ -39,7 +38,6 @@ import { MODAL_TYPES } from '../../../helpers/constants/MODAL_TYPES';
39
38
  import {
40
39
  setActiveFile,
41
40
  setActiveModal,
42
- setLangSource,
43
41
  } from '../../../roomStore/chatSettingsSlice';
44
42
  import { addRoomViaApi, setCurrentRoom } from '../../../roomStore/roomsSlice';
45
43
  import { runLogoutFlow } from '../../Menu/HeaderRoomListMenu';
@@ -51,6 +49,7 @@ import {
51
49
  } from '../../../networking/api-requests/rooms.api';
52
50
  import EncryptionCard from '../../MainComponents/EncryptionCard';
53
51
  import { accountNameOf } from '../../../helpers/accountName';
52
+ import { setChatLanguage } from '../../../services/languageSettings';
54
53
  import { composeName } from '../../../helpers/displayName';
55
54
  import { isUnresolvedSenderId } from '../../../helpers/isUnresolvedSenderId';
56
55
 
@@ -66,7 +65,7 @@ import {
66
65
  } from '../../../networking/api-requests/user.api';
67
66
  import { createRoomFromApi } from '../../../helpers/createRoomFromApi';
68
67
  import { walletToUsername } from '../../../helpers/walletUsername';
69
- import { Iso639_1Codes } from '../../../types/types';
68
+ import { } from '../../../types/types';
70
69
  import {
71
70
  ProfileHero,
72
71
  ProfileTopBar,
@@ -206,8 +205,12 @@ const UserProfileModal: React.FC<UserProfileModalProps> = ({
206
205
  // AsyncStorage), including the host's confirm copy and callbacks.
207
206
  const performLogout = useLogout();
208
207
  const handleLogout = useCallback(() => {
209
- runLogoutFlow(config?.logout ?? { enabled: true }, performLogout).catch(() => {});
210
- }, [config?.logout, performLogout]);
208
+ runLogoutFlow(config?.logout ?? { enabled: true }, performLogout, {
209
+ label: t('menu.logout'),
210
+ message: t('menu.logoutConfirm'),
211
+ cancel: t('action.cancel'),
212
+ }).catch(() => {});
213
+ }, [config?.logout, performLogout, t]);
211
214
 
212
215
  const handleShare = useCallback(async () => {
213
216
  const name =
@@ -243,8 +246,8 @@ const UserProfileModal: React.FC<UserProfileModalProps> = ({
243
246
 
244
247
  showToast({
245
248
  id: Date.now().toString(),
246
- title: 'Success!',
247
- message: 'Room created succusfully!',
249
+ title: t('toast.success'),
250
+ message: t('toast.roomCreatedSuccess'),
248
251
  type: 'success',
249
252
  duration: 3000,
250
253
  });
@@ -256,8 +259,8 @@ const UserProfileModal: React.FC<UserProfileModalProps> = ({
256
259
  const openPrivateRoom = useCallback(async (e2ee: boolean) => {
257
260
  showToast({
258
261
  id: Date.now().toString(),
259
- title: 'Room creation',
260
- message: 'Room is being created...',
262
+ title: t('toast.roomCreationTitle'),
263
+ message: t('toast.roomCreating'),
261
264
  type: 'info',
262
265
  duration: 3000,
263
266
  });
@@ -297,7 +300,7 @@ const UserProfileModal: React.FC<UserProfileModalProps> = ({
297
300
  }
298
301
 
299
302
  dispatch(setActiveModal(undefined));
300
- }, [selectedUser]); // eslint-disable-line react-hooks/exhaustive-deps
303
+ }, [selectedUser, t]); // eslint-disable-line react-hooks/exhaustive-deps
301
304
 
302
305
  const handlePrivateMessage = useCallback(
303
306
  () => openPrivateRoom(false),
@@ -430,9 +433,12 @@ const UserProfileModal: React.FC<UserProfileModalProps> = ({
430
433
  testID={`${PREFIX}-language-${option.id}`}
431
434
  activeOpacity={0.7}
432
435
  style={styles.languageRow}
433
- onPress={() =>
434
- dispatch(setLangSource(option.id as Iso639_1Codes))
435
- }
436
+ // The same choice Settings offers as "chat language": kept
437
+ // on the device, and written to the profile when the host
438
+ // turned that on.
439
+ onPress={() => {
440
+ setChatLanguage(option.id).catch(() => {});
441
+ }}
436
442
  >
437
443
  <Text style={styles.languageLabel}>{option.name}</Text>
438
444
  {selected && (
@@ -534,19 +540,6 @@ const UserProfileModal: React.FC<UserProfileModalProps> = ({
534
540
  scrollY={scrollY}
535
541
  actions={heroActions}
536
542
  titleStyle={chatTextStyle(config?.typography?.profile?.title)}
537
- titleAccessory={
538
- isOwnProfile ? (
539
- <TouchableOpacity
540
- testID={`${PREFIX}-logout`}
541
- activeOpacity={0.7}
542
- style={styles.leaveButton}
543
- onPress={handleLogout}
544
- >
545
- <LeaveIcon color="#FFFFFF" width={18} height={18} />
546
- <Text style={styles.leaveLabel}>{t('action.leave')}</Text>
547
- </TouchableOpacity>
548
- ) : undefined
549
- }
550
543
  />
551
544
 
552
545
  <View style={styles.body}>
@@ -678,20 +671,6 @@ const createStyles = (theme: ChatTheme) => StyleSheet.create({
678
671
  fontSize: 16,
679
672
  marginTop: 4,
680
673
  },
681
- leaveButton: {
682
- flexDirection: 'row',
683
- alignItems: 'center',
684
- gap: 6,
685
- paddingHorizontal: 12,
686
- paddingVertical: 7,
687
- borderRadius: 18,
688
- backgroundColor: 'rgba(0,0,0,0.35)',
689
- },
690
- leaveLabel: {
691
- color: '#FFFFFF',
692
- fontSize: 14,
693
- fontWeight: '500',
694
- },
695
674
  tabsRow: {
696
675
  flexDirection: 'row',
697
676
  gap: 20,