@ethora/chat-component-rn 26.8.7 → 26.8.8

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 (195) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +25 -3
  3. package/lib/commonjs/components/MainComponents/ChatWrapper.js +5 -3
  4. package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
  5. package/lib/commonjs/components/MainComponents/ReduxWrapper.js +8 -0
  6. package/lib/commonjs/components/MainComponents/ReduxWrapper.js.map +1 -1
  7. package/lib/commonjs/components/Menu/HeaderRoomListMenu.js +26 -13
  8. package/lib/commonjs/components/Menu/HeaderRoomListMenu.js.map +1 -1
  9. package/lib/commonjs/components/MenuRoom/MenuRoom.js +5 -3
  10. package/lib/commonjs/components/MenuRoom/MenuRoom.js.map +1 -1
  11. package/lib/commonjs/components/MessageBubble/Message.js +3 -3
  12. package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
  13. package/lib/commonjs/components/MessageBubble/MessageInteractions.js +5 -3
  14. package/lib/commonjs/components/MessageBubble/MessageInteractions.js.map +1 -1
  15. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +1 -1
  16. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  17. package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js +2 -2
  18. package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -1
  19. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +7 -5
  20. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  21. package/lib/commonjs/components/Modals/Modal/Modal.js +33 -11
  22. package/lib/commonjs/components/Modals/Modal/Modal.js.map +1 -1
  23. package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js +8 -8
  24. package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
  25. package/lib/commonjs/components/Modals/SettingsModals/ChangePassword/ChangePasswordModal.js +279 -0
  26. package/lib/commonjs/components/Modals/SettingsModals/ChangePassword/ChangePasswordModal.js.map +1 -0
  27. package/lib/commonjs/components/Modals/SettingsModals/ManageDataModal/ManageDataModal.js +10 -8
  28. package/lib/commonjs/components/Modals/SettingsModals/ManageDataModal/ManageDataModal.js.map +1 -1
  29. package/lib/commonjs/components/Modals/SettingsModals/Visibility/VisibilityModal.js +13 -11
  30. package/lib/commonjs/components/Modals/SettingsModals/Visibility/VisibilityModal.js.map +1 -1
  31. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +21 -9
  32. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  33. package/lib/commonjs/components/Modals/UserSettingsModal/LanguageCard.js +121 -0
  34. package/lib/commonjs/components/Modals/UserSettingsModal/LanguageCard.js.map +1 -0
  35. package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js +11 -6
  36. package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
  37. package/lib/commonjs/components/Thread/ThreadWrapper.js +4 -2
  38. package/lib/commonjs/components/Thread/ThreadWrapper.js.map +1 -1
  39. package/lib/commonjs/e2ee/stanza.js +1 -1
  40. package/lib/commonjs/e2ee/stanza.js.map +1 -1
  41. package/lib/commonjs/helpers/constants/MODAL_COMPONENTS.js +2 -0
  42. package/lib/commonjs/helpers/constants/MODAL_COMPONENTS.js.map +1 -1
  43. package/lib/commonjs/helpers/constants/MODAL_TYPES.js +1 -0
  44. package/lib/commonjs/helpers/constants/MODAL_TYPES.js.map +1 -1
  45. package/lib/commonjs/helpers/preferencesStorage.js.map +1 -1
  46. package/lib/commonjs/hooks/useChatSettingState.js +2 -0
  47. package/lib/commonjs/hooks/useChatSettingState.js.map +1 -1
  48. package/lib/commonjs/hooks/useChatWrapperInit.js +4 -0
  49. package/lib/commonjs/hooks/useChatWrapperInit.js.map +1 -1
  50. package/lib/commonjs/i18n/strings.js +187 -1
  51. package/lib/commonjs/i18n/strings.js.map +1 -1
  52. package/lib/commonjs/i18n/useT.js +8 -4
  53. package/lib/commonjs/i18n/useT.js.map +1 -1
  54. package/lib/commonjs/networking/api-requests/user.api.js +13 -0
  55. package/lib/commonjs/networking/api-requests/user.api.js.map +1 -1
  56. package/lib/commonjs/networking/stanzaHandlers.js +1 -1
  57. package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
  58. package/lib/commonjs/roomStore/chatSettingsSlice.js +7 -2
  59. package/lib/commonjs/roomStore/chatSettingsSlice.js.map +1 -1
  60. package/lib/commonjs/services/languageSettings.js +177 -0
  61. package/lib/commonjs/services/languageSettings.js.map +1 -0
  62. package/lib/commonjs/version.js +1 -1
  63. package/lib/module/components/MainComponents/ChatWrapper.js +5 -3
  64. package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
  65. package/lib/module/components/MainComponents/ReduxWrapper.js +9 -1
  66. package/lib/module/components/MainComponents/ReduxWrapper.js.map +1 -1
  67. package/lib/module/components/Menu/HeaderRoomListMenu.js +26 -13
  68. package/lib/module/components/Menu/HeaderRoomListMenu.js.map +1 -1
  69. package/lib/module/components/MenuRoom/MenuRoom.js +5 -3
  70. package/lib/module/components/MenuRoom/MenuRoom.js.map +1 -1
  71. package/lib/module/components/MessageBubble/Message.js +3 -3
  72. package/lib/module/components/MessageBubble/Message.js.map +1 -1
  73. package/lib/module/components/MessageBubble/MessageInteractions.js +5 -3
  74. package/lib/module/components/MessageBubble/MessageInteractions.js.map +1 -1
  75. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +1 -1
  76. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  77. package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js +2 -2
  78. package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -1
  79. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +7 -5
  80. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  81. package/lib/module/components/Modals/Modal/Modal.js +33 -11
  82. package/lib/module/components/Modals/Modal/Modal.js.map +1 -1
  83. package/lib/module/components/Modals/NewChatModal/NewChatModal.js +8 -8
  84. package/lib/module/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
  85. package/lib/module/components/Modals/SettingsModals/ChangePassword/ChangePasswordModal.js +274 -0
  86. package/lib/module/components/Modals/SettingsModals/ChangePassword/ChangePasswordModal.js.map +1 -0
  87. package/lib/module/components/Modals/SettingsModals/ManageDataModal/ManageDataModal.js +10 -8
  88. package/lib/module/components/Modals/SettingsModals/ManageDataModal/ManageDataModal.js.map +1 -1
  89. package/lib/module/components/Modals/SettingsModals/Visibility/VisibilityModal.js +13 -11
  90. package/lib/module/components/Modals/SettingsModals/Visibility/VisibilityModal.js.map +1 -1
  91. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +22 -10
  92. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  93. package/lib/module/components/Modals/UserSettingsModal/LanguageCard.js +116 -0
  94. package/lib/module/components/Modals/UserSettingsModal/LanguageCard.js.map +1 -0
  95. package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js +10 -5
  96. package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
  97. package/lib/module/components/Thread/ThreadWrapper.js +4 -2
  98. package/lib/module/components/Thread/ThreadWrapper.js.map +1 -1
  99. package/lib/module/e2ee/stanza.js +1 -1
  100. package/lib/module/e2ee/stanza.js.map +1 -1
  101. package/lib/module/helpers/constants/MODAL_COMPONENTS.js +2 -0
  102. package/lib/module/helpers/constants/MODAL_COMPONENTS.js.map +1 -1
  103. package/lib/module/helpers/constants/MODAL_TYPES.js +1 -0
  104. package/lib/module/helpers/constants/MODAL_TYPES.js.map +1 -1
  105. package/lib/module/helpers/preferencesStorage.js.map +1 -1
  106. package/lib/module/hooks/useChatSettingState.js +2 -0
  107. package/lib/module/hooks/useChatSettingState.js.map +1 -1
  108. package/lib/module/hooks/useChatWrapperInit.js +4 -0
  109. package/lib/module/hooks/useChatWrapperInit.js.map +1 -1
  110. package/lib/module/i18n/strings.js +187 -1
  111. package/lib/module/i18n/strings.js.map +1 -1
  112. package/lib/module/i18n/useT.js +8 -4
  113. package/lib/module/i18n/useT.js.map +1 -1
  114. package/lib/module/networking/api-requests/user.api.js +12 -0
  115. package/lib/module/networking/api-requests/user.api.js.map +1 -1
  116. package/lib/module/networking/stanzaHandlers.js +1 -1
  117. package/lib/module/networking/stanzaHandlers.js.map +1 -1
  118. package/lib/module/roomStore/chatSettingsSlice.js +5 -1
  119. package/lib/module/roomStore/chatSettingsSlice.js.map +1 -1
  120. package/lib/module/services/languageSettings.js +164 -0
  121. package/lib/module/services/languageSettings.js.map +1 -0
  122. package/lib/module/version.js +1 -1
  123. package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
  124. package/lib/typescript/components/MainComponents/ReduxWrapper.d.ts.map +1 -1
  125. package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts +7 -1
  126. package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts.map +1 -1
  127. package/lib/typescript/components/MenuRoom/MenuRoom.d.ts.map +1 -1
  128. package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts.map +1 -1
  129. package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
  130. package/lib/typescript/components/Modals/Modal/Modal.d.ts.map +1 -1
  131. package/lib/typescript/components/Modals/SettingsModals/ChangePassword/ChangePasswordModal.d.ts +15 -0
  132. package/lib/typescript/components/Modals/SettingsModals/ChangePassword/ChangePasswordModal.d.ts.map +1 -0
  133. package/lib/typescript/components/Modals/SettingsModals/ManageDataModal/ManageDataModal.d.ts.map +1 -1
  134. package/lib/typescript/components/Modals/SettingsModals/Visibility/VisibilityModal.d.ts.map +1 -1
  135. package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
  136. package/lib/typescript/components/Modals/UserSettingsModal/LanguageCard.d.ts +14 -0
  137. package/lib/typescript/components/Modals/UserSettingsModal/LanguageCard.d.ts.map +1 -0
  138. package/lib/typescript/components/Modals/UserSettingsModal/UserSettingsModal.d.ts.map +1 -1
  139. package/lib/typescript/components/Thread/ThreadWrapper.d.ts.map +1 -1
  140. package/lib/typescript/helpers/constants/MODAL_COMPONENTS.d.ts.map +1 -1
  141. package/lib/typescript/helpers/constants/MODAL_TYPES.d.ts +1 -0
  142. package/lib/typescript/helpers/constants/MODAL_TYPES.d.ts.map +1 -1
  143. package/lib/typescript/helpers/preferencesStorage.d.ts +4 -0
  144. package/lib/typescript/helpers/preferencesStorage.d.ts.map +1 -1
  145. package/lib/typescript/hooks/useChatSettingState.d.ts +1 -0
  146. package/lib/typescript/hooks/useChatSettingState.d.ts.map +1 -1
  147. package/lib/typescript/hooks/useChatWrapperInit.d.ts.map +1 -1
  148. package/lib/typescript/i18n/strings.d.ts.map +1 -1
  149. package/lib/typescript/i18n/useT.d.ts.map +1 -1
  150. package/lib/typescript/networking/api-requests/user.api.d.ts +6 -0
  151. package/lib/typescript/networking/api-requests/user.api.d.ts.map +1 -1
  152. package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
  153. package/lib/typescript/roomStore/chatSettingsSlice.d.ts +8 -1
  154. package/lib/typescript/roomStore/chatSettingsSlice.d.ts.map +1 -1
  155. package/lib/typescript/services/languageSettings.d.ts +29 -0
  156. package/lib/typescript/services/languageSettings.d.ts.map +1 -0
  157. package/lib/typescript/types/models/user.model.d.ts +4 -0
  158. package/lib/typescript/types/models/user.model.d.ts.map +1 -1
  159. package/lib/typescript/types/types.d.ts +21 -0
  160. package/lib/typescript/types/types.d.ts.map +1 -1
  161. package/lib/typescript/version.d.ts +1 -1
  162. package/package.json +1 -1
  163. package/src/components/MainComponents/ChatWrapper.tsx +5 -3
  164. package/src/components/MainComponents/ReduxWrapper.tsx +6 -0
  165. package/src/components/Menu/HeaderRoomListMenu.tsx +40 -13
  166. package/src/components/MenuRoom/MenuRoom.tsx +5 -3
  167. package/src/components/MessageBubble/Message.tsx +3 -3
  168. package/src/components/MessageBubble/MessageInteractions.tsx +5 -3
  169. package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +1 -1
  170. package/src/components/Modals/ChatProfileModal/ReportChatModal.tsx +2 -2
  171. package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +7 -5
  172. package/src/components/Modals/Modal/Modal.tsx +44 -16
  173. package/src/components/Modals/NewChatModal/NewChatModal.tsx +8 -8
  174. package/src/components/Modals/SettingsModals/ChangePassword/ChangePasswordModal.tsx +316 -0
  175. package/src/components/Modals/SettingsModals/ManageDataModal/ManageDataModal.tsx +10 -15
  176. package/src/components/Modals/SettingsModals/Visibility/VisibilityModal.tsx +13 -14
  177. package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +19 -12
  178. package/src/components/Modals/UserSettingsModal/LanguageCard.tsx +144 -0
  179. package/src/components/Modals/UserSettingsModal/UserSettingsModal.tsx +11 -4
  180. package/src/components/Thread/ThreadWrapper.tsx +4 -2
  181. package/src/e2ee/stanza.ts +1 -1
  182. package/src/helpers/constants/MODAL_COMPONENTS.tsx +2 -0
  183. package/src/helpers/constants/MODAL_TYPES.ts +1 -0
  184. package/src/helpers/preferencesStorage.ts +4 -0
  185. package/src/hooks/useChatSettingState.tsx +4 -0
  186. package/src/hooks/useChatWrapperInit.ts +4 -0
  187. package/src/i18n/strings.ts +187 -1
  188. package/src/i18n/useT.ts +6 -4
  189. package/src/networking/api-requests/user.api.ts +9 -0
  190. package/src/networking/stanzaHandlers.ts +1 -0
  191. package/src/roomStore/chatSettingsSlice.ts +13 -0
  192. package/src/services/languageSettings.ts +143 -0
  193. package/src/types/models/user.model.ts +4 -0
  194. package/src/types/types.ts +21 -0
  195. package/src/version.ts +1 -1
@@ -30,14 +30,27 @@ import {
30
30
  shouldDismissOnDrag,
31
31
  } from '../../helpers/sheetGestures';
32
32
  import type { IConfig } from '../../types/types';
33
+ import { useT } from '../../i18n/useT';
33
34
 
34
35
  type LogoutConfig = NonNullable<IConfig['logout']>;
35
36
 
36
- const DEFAULT_LOGOUT_LABEL = 'Sign out';
37
+ /** The sign-out copy in the UI language; a host's `logout.label` etc. win. */
38
+ export interface LogoutStrings {
39
+ label: string;
40
+ message: string;
41
+ cancel: string;
42
+ }
43
+
44
+ const DEFAULT_LOGOUT_STRINGS: LogoutStrings = {
45
+ label: 'Sign out',
46
+ message: 'Are you sure you want to sign out?',
47
+ cancel: 'Cancel',
48
+ };
37
49
 
38
50
  const confirmLogout = (
39
51
  confirm: LogoutConfig['confirm'],
40
- label: string
52
+ label: string,
53
+ strings: LogoutStrings
41
54
  ): Promise<boolean> => {
42
55
  if (confirm === false) {
43
56
  return Promise.resolve(true);
@@ -46,10 +59,10 @@ const confirmLogout = (
46
59
  return new Promise<boolean>((resolve) => {
47
60
  Alert.alert(
48
61
  copy.title ?? label,
49
- copy.message ?? 'Are you sure you want to sign out?',
62
+ copy.message ?? strings.message,
50
63
  [
51
64
  {
52
- text: copy.cancelText ?? 'Cancel',
65
+ text: copy.cancelText ?? strings.cancel,
53
66
  style: 'cancel',
54
67
  onPress: () => resolve(false),
55
68
  },
@@ -66,10 +79,15 @@ const confirmLogout = (
66
79
 
67
80
  export const runLogoutFlow = async (
68
81
  logoutConfig: LogoutConfig,
69
- performLogout: () => Promise<void>
82
+ performLogout: () => Promise<void>,
83
+ strings: LogoutStrings = DEFAULT_LOGOUT_STRINGS
70
84
  ): Promise<void> => {
71
- const label = logoutConfig.label ?? DEFAULT_LOGOUT_LABEL;
72
- const confirmed = await confirmLogout(logoutConfig.confirm ?? true, label);
85
+ const label = logoutConfig.label ?? strings.label;
86
+ const confirmed = await confirmLogout(
87
+ logoutConfig.confirm ?? true,
88
+ label,
89
+ strings
90
+ );
73
91
  if (!confirmed) {
74
92
  return;
75
93
  }
@@ -112,7 +130,16 @@ export const HeaderRoomListMenu: FC<HeaderRoomListMenuProps> = ({
112
130
  const dispatch = useDispatch();
113
131
  const { config } = useChatSettingState();
114
132
  const performLogout = useLogout();
133
+ const t = useT();
115
134
  const logoutConfig = config?.logout?.enabled ? config.logout : undefined;
135
+ const logoutStrings = useMemo<LogoutStrings>(
136
+ () => ({
137
+ label: t('menu.logout'),
138
+ message: t('menu.logoutConfirm'),
139
+ cancel: t('action.cancel'),
140
+ }),
141
+ [t]
142
+ );
116
143
  const theme = useTheme();
117
144
  const primaryColor = theme.primary;
118
145
  const iconColor = theme.icon;
@@ -246,7 +273,7 @@ export const HeaderRoomListMenu: FC<HeaderRoomListMenuProps> = ({
246
273
  styles?: { color: string };
247
274
  }[] = [
248
275
  {
249
- label: 'New Chat',
276
+ label: t('menu.newChat'),
250
277
  icon: <AddNewIcon color={iconColor} />,
251
278
  onClick: () => {
252
279
  dispatch(setActiveModal(MODAL_TYPES.NEW_CHAT));
@@ -254,14 +281,14 @@ export const HeaderRoomListMenu: FC<HeaderRoomListMenuProps> = ({
254
281
  styles: { color: labelColor },
255
282
  },
256
283
  {
257
- label: 'Profile',
284
+ label: t('menu.profile'),
258
285
  icon: <ProfileIcon color={iconColor} />,
259
286
  onClick: () => {
260
287
  dispatch(setActiveModal(MODAL_TYPES.PROFILE));
261
288
  },
262
289
  },
263
290
  {
264
- label: 'Settings',
291
+ label: t('menu.settings'),
265
292
  icon: <SettingIcon color={iconColor} />,
266
293
  onClick: () => {
267
294
  dispatch(setActiveModal(MODAL_TYPES.SETTINGS));
@@ -270,16 +297,16 @@ export const HeaderRoomListMenu: FC<HeaderRoomListMenuProps> = ({
270
297
  ];
271
298
  if (logoutConfig) {
272
299
  options.push({
273
- label: logoutConfig.label ?? DEFAULT_LOGOUT_LABEL,
300
+ label: logoutConfig.label ?? logoutStrings.label,
274
301
  icon: <LogoutIcon color={iconColor} />,
275
302
  styles: { color: primaryColor },
276
303
  onClick: () => {
277
- runLogoutFlow(logoutConfig, performLogout).catch(() => {});
304
+ runLogoutFlow(logoutConfig, performLogout, logoutStrings).catch(() => {});
278
305
  },
279
306
  });
280
307
  }
281
308
  return options;
282
- }, [dispatch, logoutConfig, performLogout, primaryColor, iconColor, labelColor]);
309
+ }, [dispatch, logoutConfig, logoutStrings, performLogout, primaryColor, iconColor, labelColor, t]);
283
310
 
284
311
  return (
285
312
  // Presented through a real <Modal>: as an in-tree overlay the sheet was
@@ -2,16 +2,18 @@ import { FC, useMemo } from 'react';
2
2
  import DropdownMenu from '../DropdownMenu/DropdownMenu';
3
3
  import Button from '../styled/Button';
4
4
  import { LeaveIcon, MoreIcon, ReportIcon } from '../../assets/icons';
5
+ import { useT } from '../../i18n/useT';
5
6
 
6
7
  interface RoomMenuProps {
7
8
  handleLeaveClick: () => void;
8
9
  }
9
10
 
10
11
  export const RoomMenu: FC<RoomMenuProps> = ({ handleLeaveClick }) => {
12
+ const t = useT();
11
13
  const menuOptions = useMemo(
12
14
  () => [
13
15
  {
14
- label: 'Report',
16
+ label: t('action.report'),
15
17
  icon: <ReportIcon />,
16
18
  onClick: () => {
17
19
  console.log('Report clicked');
@@ -19,7 +21,7 @@ export const RoomMenu: FC<RoomMenuProps> = ({ handleLeaveClick }) => {
19
21
  styles: { color: 'red' },
20
22
  },
21
23
  {
22
- label: 'Leave',
24
+ label: t('action.leave'),
23
25
  icon: <LeaveIcon />,
24
26
  onClick: () => {
25
27
  handleLeaveClick();
@@ -27,7 +29,7 @@ export const RoomMenu: FC<RoomMenuProps> = ({ handleLeaveClick }) => {
27
29
  styles: { color: 'red' },
28
30
  },
29
31
  ],
30
- [handleLeaveClick]
32
+ [handleLeaveClick, t]
31
33
  );
32
34
 
33
35
  return (
@@ -644,7 +644,7 @@ const Message: React.FC<MessageProps> = ({ message, isUser, isReply }) => {
644
644
  <CustomTimestampRow media={message?.isMediafile === 'true'}>
645
645
  {!config?.disableSentLogic && isUser && isPending && (
646
646
  <Text style={[styles.timestampText, themedStyles.muted]}>
647
- sending...
647
+ {t('message.sending')}
648
648
  </Text>
649
649
  )}
650
650
  {!config?.disableSentLogic && isUser && isFailed && (
@@ -654,11 +654,11 @@ const Message: React.FC<MessageProps> = ({ message, isUser, isReply }) => {
654
654
  accessibilityRole="button"
655
655
  accessibilityLabel="Retry sending message"
656
656
  >
657
- ! Failed — tap to retry
657
+ {t('message.failedRetry')}
658
658
  </Text>
659
659
  )}
660
660
  {message?.isEdited && !message?.isDeleted && (
661
- <Text style={[styles.editedText, themedStyles.muted]}>edited</Text>
661
+ <Text style={[styles.editedText, themedStyles.muted]}>{t('message.edited')}</Text>
662
662
  )}
663
663
  {message?.unencrypted && !message?.isDeleted && (
664
664
  <Pressable
@@ -22,6 +22,7 @@ import * as Clipboard from 'expo-clipboard';
22
22
  import { useToast } from '../../context/ToastContext';
23
23
  import { useInteractionsOverlay } from './InteractionsOverlay';
24
24
  import { useTheme } from '../../hooks/useTheme';
25
+ import { useT } from '../../i18n/useT';
25
26
  import { getEmojiNativeById } from '../../helpers/emoji';
26
27
  import {
27
28
  quickReactionIds,
@@ -61,6 +62,7 @@ const MessageInteractions: React.FC<MessageInteractionsProps> = ({
61
62
  onOpenEmojiPicker,
62
63
  }) => {
63
64
  const { showToast } = useToast();
65
+ const t = useT();
64
66
  const { present, dismiss, originX, originY } = useInteractionsOverlay();
65
67
  const overlayId = useId();
66
68
  const theme = useTheme();
@@ -144,15 +146,15 @@ const MessageInteractions: React.FC<MessageInteractionsProps> = ({
144
146
  await Clipboard.setStringAsync(text);
145
147
  showToast({
146
148
  id: Date.now().toString(),
147
- title: 'Success',
148
- message: 'Copied to clipboard!',
149
+ title: t('toast.successTitle'),
150
+ message: t('toast.copied'),
149
151
  type: 'success',
150
152
  });
151
153
  } catch (err) {
152
154
  console.log(err);
153
155
  showToast({
154
156
  id: Date.now().toString(),
155
- title: 'Copy failed',
157
+ title: t('toast.copyFailed'),
156
158
  message: (err as Error)?.message || 'Unknown error',
157
159
  type: 'error',
158
160
  });
@@ -379,7 +379,7 @@ const ChatProfileModal: React.FC<ChatProfileModalProps> = ({
379
379
  console.warn('[ethora-rn] mute toggle failed', error);
380
380
  showToast({
381
381
  id: Date.now().toString(),
382
- title: 'Error',
382
+ title: t('toast.error'),
383
383
  message: t('toast.muteFailed'),
384
384
  type: 'error',
385
385
  });
@@ -72,7 +72,7 @@ const ReportChatModal: React.FC<ReportChatModalProps> = ({
72
72
  });
73
73
  showToast({
74
74
  id: Date.now().toString(),
75
- title: 'Success',
75
+ title: t('toast.successTitle'),
76
76
  message: t('modal.report.chatTitle'),
77
77
  type: 'success',
78
78
  });
@@ -81,7 +81,7 @@ const ReportChatModal: React.FC<ReportChatModalProps> = ({
81
81
  console.error('Failed to report chat:', error);
82
82
  showToast({
83
83
  id: Date.now().toString(),
84
- title: 'Error',
84
+ title: t('toast.error'),
85
85
  message: t('modal.report.chatTitle'),
86
86
  type: 'error',
87
87
  });
@@ -30,6 +30,7 @@ import { PlayIcon } from '../../../assets/icons';
30
30
  import * as FileSystem from 'expo-file-system/legacy';
31
31
  import { getMediaLibrary } from '../../../helpers/mediaLibraryRuntime';
32
32
  import { useToast } from '../../../context/ToastContext';
33
+ import { useT } from '../../../i18n/useT';
33
34
  import PdfViewer from './PdfView';
34
35
  import DocumentViewer from './DocumentViewer';
35
36
  import AudioMessage from '../../styled/AudioMessage';
@@ -250,6 +251,7 @@ const FilePreviewModal: React.FC<FilePreviewModalProps> = ({
250
251
  }) => {
251
252
  const dispatch = useDispatch();
252
253
  const { showToast } = useToast();
254
+ const t = useT();
253
255
  const { config } = useChatSettingState();
254
256
  const theme = useTheme();
255
257
  // Info / audio cards: light keeps its warm tint (not in the palette),
@@ -309,8 +311,8 @@ const FilePreviewModal: React.FC<FilePreviewModalProps> = ({
309
311
  await getMediaLibrary()?.saveToLibraryAsync(download.uri);
310
312
  showToast({
311
313
  id: Date.now().toString(),
312
- title: 'Success',
313
- message: 'Save successful',
314
+ title: t('toast.successTitle'),
315
+ message: t('toast.saveSuccessful'),
314
316
  type: 'success',
315
317
  });
316
318
  } else {
@@ -394,8 +396,8 @@ const FilePreviewModal: React.FC<FilePreviewModalProps> = ({
394
396
 
395
397
  showToast({
396
398
  id: Date.now().toString(),
397
- title: 'Success',
398
- message: 'Save successful',
399
+ title: t('toast.successTitle'),
400
+ message: t('toast.saveSuccessful'),
399
401
  type: 'success',
400
402
  });
401
403
  return;
@@ -576,7 +578,7 @@ const FilePreviewModal: React.FC<FilePreviewModalProps> = ({
576
578
  <ModalContainerFullScreen>
577
579
  <ModalHeaderComponent
578
580
  handleCloseModal={closeModal}
579
- headerTitle={'File preview'}
581
+ headerTitle={t('modal.filePreview.title')}
580
582
  titleStyle={chatTextStyle(config?.typography?.profile?.screenTitle)}
581
583
  rightMenu={
582
584
  <>
@@ -16,6 +16,17 @@ interface ModalProps {
16
16
  setOpenModal: (value?: ModalType) => any;
17
17
  }
18
18
 
19
+ /** Screens reached from Settings: closing them goes back there. */
20
+ const SETTINGS_SCREENS = new Set<string>([
21
+ MODAL_TYPES.MANAGE_DATA,
22
+ MODAL_TYPES.VISIBILITY,
23
+ MODAL_TYPES.REFERRALS,
24
+ MODAL_TYPES.DOCUMENT_SHARES,
25
+ MODAL_TYPES.PROFILE_SHARES,
26
+ MODAL_TYPES.BLOCKED_USERS,
27
+ MODAL_TYPES.CHANGE_PASSWORD,
28
+ ]);
29
+
19
30
  const Modal: React.FC<ModalProps> = ({ children, modal, setOpenModal }) => {
20
31
  const dispatch = useDispatch();
21
32
  const handleCloseModal = () => setOpenModal();
@@ -29,15 +40,9 @@ const Modal: React.FC<ModalProps> = ({ children, modal, setOpenModal }) => {
29
40
 
30
41
  if (!ModalComponent) {return null;}
31
42
 
32
- const handleClose =
33
- modal === MODAL_TYPES.MANAGE_DATA ||
34
- modal === MODAL_TYPES.VISIBILITY ||
35
- modal === MODAL_TYPES.REFERRALS ||
36
- modal === MODAL_TYPES.DOCUMENT_SHARES ||
37
- modal === MODAL_TYPES.PROFILE_SHARES ||
38
- modal === MODAL_TYPES.BLOCKED_USERS
39
- ? handleBackButtonClick
40
- : handleCloseModal;
43
+ const handleClose = SETTINGS_SCREENS.has(modal)
44
+ ? handleBackButtonClick
45
+ : handleCloseModal;
41
46
 
42
47
  return <ModalComponent handleCloseModal={handleClose} />;
43
48
  };
@@ -75,15 +80,38 @@ const Modal: React.FC<ModalProps> = ({ children, modal, setOpenModal }) => {
75
80
  }
76
81
  }
77
82
 
83
+ // Screens under Settings are pages too: they slide in over Settings and
84
+ // a swipe from the left edge takes them back to it, same as the header's
85
+ // back button. Settings stays mounted underneath the whole time, so the
86
+ // slide reveals it - not the chat list - and nothing is rebuilt once the
87
+ // page has gone. The elements below keep the same shape as the plain
88
+ // branch, so Settings is the same instance before, during and after.
89
+ const subScreen = modal && SETTINGS_SCREENS.has(modal) ? modal : undefined;
90
+ const SubScreenComponent = subScreen ? MODAL_COMPONENTS[subScreen] : undefined;
91
+ const SettingsComponent = MODAL_COMPONENTS[MODAL_TYPES.SETTINGS];
92
+ const underneath =
93
+ SubScreenComponent && SettingsComponent ? (
94
+ <SettingsComponent handleCloseModal={handleCloseModal} />
95
+ ) : (
96
+ renderModalContent()
97
+ );
98
+
78
99
  return (
79
100
  modal && (
80
- <ModalBackground
81
- id="modal-background"
82
- style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 }}
83
- >
84
- {renderModalContent()}
85
- {children}
86
- </ModalBackground>
101
+ <>
102
+ <ModalBackground
103
+ id="modal-background"
104
+ style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 }}
105
+ >
106
+ {underneath}
107
+ {children}
108
+ </ModalBackground>
109
+ {SubScreenComponent && (
110
+ <SwipeBackLayer onClose={handleBackButtonClick}>
111
+ {(close) => <SubScreenComponent handleCloseModal={close} />}
112
+ </SwipeBackLayer>
113
+ )}
114
+ </>
87
115
  )
88
116
  );
89
117
  };
@@ -187,16 +187,16 @@ const NewChatModal: React.FC<NewChatModalProps> = ({
187
187
 
188
188
  showToast({
189
189
  id: Date.now().toString(),
190
- title: 'Success',
191
- message: 'Room created successfully',
190
+ title: t('toast.successTitle'),
191
+ message: t('toast.roomCreatedSuccess'),
192
192
  type: 'success',
193
193
  });
194
194
  } catch (error) {
195
195
  console.error('Error handling room creation:', error);
196
196
  showToast({
197
197
  id: Date.now().toString(),
198
- title: 'Error',
199
- message: 'Failed to create room',
198
+ title: t('toast.error'),
199
+ message: t('toast.failedToCreateRoom'),
200
200
  type: 'error',
201
201
  });
202
202
  }
@@ -258,8 +258,8 @@ const NewChatModal: React.FC<NewChatModalProps> = ({
258
258
 
259
259
  showToast({
260
260
  id: Date.now().toString(),
261
- title: 'Success',
262
- message: 'Room created successfully',
261
+ title: t('toast.successTitle'),
262
+ message: t('toast.roomCreatedSuccess'),
263
263
  type: 'success',
264
264
  });
265
265
  handleCloseModal();
@@ -267,8 +267,8 @@ const NewChatModal: React.FC<NewChatModalProps> = ({
267
267
  console.error('Failed to create room:', error);
268
268
  showToast({
269
269
  id: Date.now().toString(),
270
- title: 'Error',
271
- message: 'Failed to create room',
270
+ title: t('toast.error'),
271
+ message: t('toast.failedToCreateRoom'),
272
272
  type: 'error',
273
273
  });
274
274
  }