From 9cbffff2484a5485b8316db6a6001def52c892f8 Mon Sep 17 00:00:00 2001 From: Reinaldo Neto <47038980+reinaldonetof@users.noreply.github.com> Date: Fri, 26 Aug 2022 16:16:45 -0300 Subject: [PATCH] [IMPROVE] Redesign create room flow (#4381) Co-authored-by: Diego Mello --- .storybook/storybook.requires.js | 2 + .../Chip/__snapshots__/Chip.stories.storyshot | 11 + .../SwitchItem.stories.storyshot | 3 + app/containers/Chip/Chip.stories.tsx | 32 ++ app/containers/Chip/Chip.test.tsx | 58 +++ app/containers/Chip/index.tsx | 75 +++ .../TextInput/ControlledFormTextInput.tsx | 17 + app/containers/TextInput/index.ts | 1 + app/containers/UserItem.tsx | 17 +- app/i18n/locales/ar.json | 5 +- app/i18n/locales/de.json | 8 +- app/i18n/locales/en.json | 26 +- app/i18n/locales/es-ES.json | 5 +- app/i18n/locales/fr.json | 8 +- app/i18n/locales/it.json | 5 +- app/i18n/locales/ja.json | 5 +- app/i18n/locales/nl.json | 8 +- app/i18n/locales/pt-BR.json | 24 +- app/i18n/locales/pt-PT.json | 5 +- app/i18n/locales/ru.json | 8 +- app/i18n/locales/tr.json | 5 +- app/i18n/locales/zh-CN.json | 5 +- app/i18n/locales/zh-TW.json | 5 +- app/stacks/InsideStack.tsx | 10 +- app/stacks/MasterDetailStack/index.tsx | 4 +- app/views/CreateChannelView.tsx | 427 ------------------ .../RoomSettings/SwitchItem.stories.tsx | 40 ++ .../RoomSettings/SwitchItem.test.tsx | 68 +++ .../RoomSettings/SwitchItem.tsx | 59 +++ .../RoomSettings/SwitchItemEncrypted.test.tsx | 108 +++++ .../RoomSettings/SwitchItemEncrypted.tsx | 48 ++ .../RoomSettings/SwitchItemReadOnly.tsx | 37 ++ .../RoomSettings/SwitchItemType.tsx | 43 ++ .../CreateChannelView/RoomSettings/index.tsx | 78 ++++ app/views/CreateChannelView/index.tsx | 205 +++++++++ app/views/NewMessageView.tsx | 335 -------------- app/views/NewMessageView/ButtonCreate.tsx | 32 ++ app/views/NewMessageView/HeaderNewMessage.tsx | 107 +++++ app/views/NewMessageView/index.tsx | 115 +++++ app/views/RoomInfoEditView/index.tsx | 2 +- app/views/RoomInfoView/Channel.tsx | 4 +- app/views/RoomMembersView/helpers.ts | 1 + app/views/SelectedUsersView.tsx | 291 ------------ app/views/SelectedUsersView/Header.tsx | 74 +++ app/views/SelectedUsersView/index.tsx | 180 ++++++++ e2e/helpers/app.js | 3 +- e2e/tests/assorted/02-broadcast.spec.js | 2 +- e2e/tests/assorted/03-profile.spec.js | 2 +- e2e/tests/room/04-discussion.spec.js | 2 +- e2e/tests/room/06-createdmgroup.spec.js | 2 +- e2e/tests/room/08-roominfo.spec.js | 24 +- e2e/tests/team/01-createteam.spec.js | 3 + package.json | 5 +- yarn.lock | 50 +- 54 files changed, 1532 insertions(+), 1167 deletions(-) create mode 100644 __tests__/containers/Chip/__snapshots__/Chip.stories.storyshot create mode 100644 __tests__/views/CreateChannelView/RoomSettings/__snapshots__/SwitchItem.stories.storyshot create mode 100644 app/containers/Chip/Chip.stories.tsx create mode 100644 app/containers/Chip/Chip.test.tsx create mode 100644 app/containers/Chip/index.tsx create mode 100644 app/containers/TextInput/ControlledFormTextInput.tsx delete mode 100644 app/views/CreateChannelView.tsx create mode 100644 app/views/CreateChannelView/RoomSettings/SwitchItem.stories.tsx create mode 100644 app/views/CreateChannelView/RoomSettings/SwitchItem.test.tsx create mode 100644 app/views/CreateChannelView/RoomSettings/SwitchItem.tsx create mode 100644 app/views/CreateChannelView/RoomSettings/SwitchItemEncrypted.test.tsx create mode 100644 app/views/CreateChannelView/RoomSettings/SwitchItemEncrypted.tsx create mode 100644 app/views/CreateChannelView/RoomSettings/SwitchItemReadOnly.tsx create mode 100644 app/views/CreateChannelView/RoomSettings/SwitchItemType.tsx create mode 100644 app/views/CreateChannelView/RoomSettings/index.tsx create mode 100644 app/views/CreateChannelView/index.tsx delete mode 100644 app/views/NewMessageView.tsx create mode 100644 app/views/NewMessageView/ButtonCreate.tsx create mode 100644 app/views/NewMessageView/HeaderNewMessage.tsx create mode 100644 app/views/NewMessageView/index.tsx delete mode 100644 app/views/SelectedUsersView.tsx create mode 100644 app/views/SelectedUsersView/Header.tsx create mode 100644 app/views/SelectedUsersView/index.tsx diff --git a/.storybook/storybook.requires.js b/.storybook/storybook.requires.js index 4f02264ec..1baa14ff4 100644 --- a/.storybook/storybook.requires.js +++ b/.storybook/storybook.requires.js @@ -22,6 +22,7 @@ const getStories = () => { require("../app/containers/Avatar/Avatar.stories.tsx"), require("../app/containers/BackgroundContainer/index.stories.tsx"), require("../app/containers/Button/Button.stories.tsx"), + require("../app/containers/Chip/Chip.stories.tsx"), require("../app/containers/HeaderButton/HeaderButtons.stories.tsx"), require("../app/containers/List/List.stories.tsx"), require("../app/containers/LoginServices/LoginServices.stories.tsx"), @@ -38,6 +39,7 @@ const getStories = () => { require("../app/containers/UIKit/UiKitModal.stories.tsx"), require("../app/containers/UnreadBadge/UnreadBadge.stories.tsx"), require("../app/views/CannedResponsesListView/CannedResponseItem.stories.tsx"), + require("../app/views/CreateChannelView/RoomSettings/SwitchItem.stories.tsx"), require("../app/views/DiscussionsView/Item.stories.tsx"), require("../app/views/RoomView/LoadMore/LoadMore.stories.tsx"), require("../app/views/ThreadMessagesView/Item.stories.tsx"), diff --git a/__tests__/containers/Chip/__snapshots__/Chip.stories.storyshot b/__tests__/containers/Chip/__snapshots__/Chip.stories.storyshot new file mode 100644 index 000000000..83a6eb4de --- /dev/null +++ b/__tests__/containers/Chip/__snapshots__/Chip.stories.storyshot @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Storyshots Chip Chip Text 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"alignItems\\":\\"flex-start\\",\\"padding\\":16}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityState\\":{\\"disabled\\":false},\\"focusable\\":true,\\"style\\":[{\\"paddingHorizontal\\":8,\\"marginRight\\":8,\\"borderRadius\\":2,\\"justifyContent\\":\\"center\\",\\"maxWidth\\":192},{\\"backgroundColor\\":\\"#efeff4\\"},null],\\"collapsable\\":false},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"marginRight\\":8,\\"maxWidth\\":120}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":16,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\"}],\\"numberOfLines\\":1},\\"children\\":[\\"Rocket.Cat\\"]}]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":16,\\"color\\":\\"#6C727A\\"},null,{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]}]}]}]}"`; + +exports[`Storyshots Chip Chip With Short Text 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"alignItems\\":\\"flex-start\\",\\"padding\\":16}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityState\\":{\\"disabled\\":false},\\"focusable\\":true,\\"style\\":[{\\"paddingHorizontal\\":8,\\"marginRight\\":8,\\"borderRadius\\":2,\\"justifyContent\\":\\"center\\",\\"maxWidth\\":192},{\\"backgroundColor\\":\\"#efeff4\\"},null],\\"collapsable\\":false},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"marginRight\\":8,\\"maxWidth\\":120}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":16,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\"}],\\"numberOfLines\\":1},\\"children\\":[\\"Short\\"]}]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":16,\\"color\\":\\"#6C727A\\"},null,{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]}]}]}]}"`; + +exports[`Storyshots Chip Chip Without Avatar 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"alignItems\\":\\"flex-start\\",\\"padding\\":16}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityState\\":{\\"disabled\\":false},\\"focusable\\":true,\\"style\\":[{\\"paddingHorizontal\\":8,\\"marginRight\\":8,\\"borderRadius\\":2,\\"justifyContent\\":\\"center\\",\\"maxWidth\\":192},{\\"backgroundColor\\":\\"#efeff4\\"},null],\\"collapsable\\":false},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"marginRight\\":8,\\"maxWidth\\":120}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":16,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\"}],\\"numberOfLines\\":1},\\"children\\":[\\"Without Avatar\\"]}]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":16,\\"color\\":\\"#6C727A\\"},null,{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]}]}]}]}"`; + +exports[`Storyshots Chip Chip Without Avatar And Icon 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"alignItems\\":\\"flex-start\\",\\"padding\\":16}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityState\\":{\\"disabled\\":true},\\"focusable\\":true,\\"style\\":[{\\"paddingHorizontal\\":8,\\"marginRight\\":8,\\"borderRadius\\":2,\\"justifyContent\\":\\"center\\",\\"maxWidth\\":192},{\\"backgroundColor\\":\\"#efeff4\\"},null],\\"collapsable\\":false},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"marginRight\\":8,\\"maxWidth\\":120}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":16,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\"}],\\"numberOfLines\\":1},\\"children\\":[\\"Without Avatar and Icon\\"]}]}]}]}]}"`; + +exports[`Storyshots Chip Chip Without Icon 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"alignItems\\":\\"flex-start\\",\\"padding\\":16}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityState\\":{\\"disabled\\":true},\\"focusable\\":true,\\"style\\":[{\\"paddingHorizontal\\":8,\\"marginRight\\":8,\\"borderRadius\\":2,\\"justifyContent\\":\\"center\\",\\"maxWidth\\":192},{\\"backgroundColor\\":\\"#efeff4\\"},null],\\"collapsable\\":false},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"marginRight\\":8,\\"maxWidth\\":120}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":16,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\"}],\\"numberOfLines\\":1},\\"children\\":[\\"Without Icon\\"]}]}]}]}]}"`; diff --git a/__tests__/views/CreateChannelView/RoomSettings/__snapshots__/SwitchItem.stories.storyshot b/__tests__/views/CreateChannelView/RoomSettings/__snapshots__/SwitchItem.stories.storyshot new file mode 100644 index 000000000..4012a3d13 --- /dev/null +++ b/__tests__/views/CreateChannelView/RoomSettings/__snapshots__/SwitchItem.stories.storyshot @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Storyshots SwitchItem Switch 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"alignItems\\":\\"flex-start\\",\\"padding\\":16}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"minHeight\\":54,\\"alignItems\\":\\"center\\",\\"justifyContent\\":\\"space-between\\",\\"flexDirection\\":\\"row\\",\\"maxHeight\\":80,\\"marginBottom\\":12},{\\"backgroundColor\\":\\"#ffffff\\"}]},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"marginRight\\":8}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":14,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#0d0e12\\"}]},\\"children\\":[\\"Welcome to Rocket.Chat\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"testID\\":\\"create-channel-switch-id-hint\\",\\"style\\":[{\\"fontSize\\":14,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"400\\"},{\\"color\\":\\"#9ca2a8\\"}]},\\"children\\":[\\"Only authorized users can write new messages\\"]}]},{\\"type\\":\\"RCTSwitch\\",\\"props\\":{\\"testID\\":\\"create-channel-switch-id\\",\\"disabled\\":false,\\"onTintColor\\":\\"#2de0a5\\",\\"style\\":{\\"height\\":31,\\"width\\":51},\\"tintColor\\":\\"#f5455c\\",\\"value\\":false,\\"accessibilityRole\\":\\"switch\\"},\\"children\\":null}]}]}"`; diff --git a/app/containers/Chip/Chip.stories.tsx b/app/containers/Chip/Chip.stories.tsx new file mode 100644 index 000000000..f4a83eda1 --- /dev/null +++ b/app/containers/Chip/Chip.stories.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { StyleSheet, View } from 'react-native'; + +import Chip, { IChip } from './index'; + +const styles = StyleSheet.create({ + container: { + flex: 1, + alignItems: 'flex-start', + padding: 16 + } +}); + +export default { + title: 'Chip' +}; + +const ChipWrapped = ({ avatar, text, onPress, testID, style }: IChip) => ( + + + +); + +export const ChipText = () => {}} />; + +export const ChipWithShortText = () => {}} />; + +export const ChipWithoutAvatar = () => {}} />; + +export const ChipWithoutIcon = () => ; + +export const ChipWithoutAvatarAndIcon = () => ; diff --git a/app/containers/Chip/Chip.test.tsx b/app/containers/Chip/Chip.test.tsx new file mode 100644 index 000000000..c222b91c3 --- /dev/null +++ b/app/containers/Chip/Chip.test.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { fireEvent, render } from '@testing-library/react-native'; +import { Provider } from 'react-redux'; + +import Chip, { IChip } from '.'; +import { ISelectedUser } from '../../reducers/selectedUsers'; +import { mockedStore as store } from '../../reducers/mockedStore'; + +const onPressMock = jest.fn((item: any) => item); + +const testChip = { + testID: 'test-chip-id', + item: { fname: 'rocket.chat', name: 'rocket.chat' } as ISelectedUser, + onPress: onPressMock +}; + +const Render = ({ testID, text, avatar, onPress }: IChip) => ( + + + +); + +describe('Chips', () => { + it('should render the Chip component', () => { + const { findByTestId } = render( + testChip.onPress(testChip.item)} + /> + ); + + expect(findByTestId(testChip.testID)).toBeTruthy(); + }); + it("should not call onPress if it's not passed", async () => { + const { findByTestId } = render(); + + const component = await findByTestId(testChip.testID); + fireEvent.press(component); + expect(onPressMock).not.toHaveBeenCalled(); + }); + it('should tap Chip and return item', async () => { + const { findByTestId } = render( + testChip.onPress(testChip.item)} + /> + ); + + const component = await findByTestId(testChip.testID); + fireEvent.press(component); + expect(onPressMock).toHaveBeenCalled(); + expect(onPressMock).toHaveReturnedWith(testChip.item); + }); +}); diff --git a/app/containers/Chip/index.tsx b/app/containers/Chip/index.tsx new file mode 100644 index 000000000..a01dfc258 --- /dev/null +++ b/app/containers/Chip/index.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { Pressable, StyleSheet, View, Text, StyleProp, ViewStyle } from 'react-native'; + +import { useTheme } from '../../theme'; +import { CustomIcon } from '../CustomIcon'; +import sharedStyles from '../../views/Styles'; +import Avatar from '../Avatar'; + +const styles = StyleSheet.create({ + pressable: { + paddingHorizontal: 8, + marginRight: 8, + borderRadius: 2, + justifyContent: 'center', + maxWidth: 192 + }, + container: { + flexDirection: 'row', + alignItems: 'center' + }, + avatar: { + marginRight: 8, + marginVertical: 8 + }, + textContainer: { + marginRight: 8, + maxWidth: 120 + }, + name: { + fontSize: 16, + ...sharedStyles.textMedium + } +}); + +export interface IChip { + avatar?: string; + text: string; + onPress?: Function; + testID?: string; + style?: StyleProp; +} + +const Chip = ({ avatar, text, onPress, testID, style }: IChip) => { + const { colors } = useTheme(); + + return ( + [ + styles.pressable, + { + backgroundColor: pressed ? colors.bannerBackground : colors.auxiliaryBackground + }, + style + ]} + disabled={!onPress} + onPress={() => onPress?.()} + android_ripple={{ + color: colors.bannerBackground + }} + > + + {avatar ? : null} + + + {text} + + + {onPress ? : null} + + + ); +}; + +export default Chip; diff --git a/app/containers/TextInput/ControlledFormTextInput.tsx b/app/containers/TextInput/ControlledFormTextInput.tsx new file mode 100644 index 000000000..5b69b0e20 --- /dev/null +++ b/app/containers/TextInput/ControlledFormTextInput.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { Control, Controller } from 'react-hook-form'; + +import { FormTextInput, IRCTextInputProps } from './FormTextInput'; + +interface IControlledFormTextInputProps extends IRCTextInputProps { + control: Control; + name: string; +} + +export const ControlledFormTextInput = ({ control, name, ...props }: IControlledFormTextInputProps) => ( + } + /> +); diff --git a/app/containers/TextInput/index.ts b/app/containers/TextInput/index.ts index 48a640fc2..a9b215823 100644 --- a/app/containers/TextInput/index.ts +++ b/app/containers/TextInput/index.ts @@ -1,2 +1,3 @@ export * from './TextInput'; export * from './FormTextInput'; +export * from './ControlledFormTextInput'; diff --git a/app/containers/UserItem.tsx b/app/containers/UserItem.tsx index e044dd6ba..02739d2f8 100644 --- a/app/containers/UserItem.tsx +++ b/app/containers/UserItem.tsx @@ -25,13 +25,9 @@ const styles = StyleSheet.create({ marginRight: 15 }, name: { - fontSize: 17, + fontSize: 16, ...sharedStyles.textMedium }, - username: { - fontSize: 14, - ...sharedStyles.textRegular - }, icon: { marginHorizontal: 15, alignSelf: 'center' @@ -46,10 +42,12 @@ interface IUserItem { onLongPress?: () => void; style?: StyleProp; icon?: TIconsName | null; + iconColor?: string; } -const UserItem = ({ name, username, onPress, testID, onLongPress, style, icon }: IUserItem): React.ReactElement => { +const UserItem = ({ name, username, onPress, testID, onLongPress, style, icon, iconColor }: IUserItem) => { const { colors } = useTheme(); + return ( - + {name} - - @{username} - - {icon ? : null} + {icon ? : null} ); diff --git a/app/i18n/locales/ar.json b/app/i18n/locales/ar.json index 2315fbf7e..ecfc038dd 100644 --- a/app/i18n/locales/ar.json +++ b/app/i18n/locales/ar.json @@ -117,8 +117,7 @@ "Black": "أسود", "Block_user": "حظر المستخدم", "Browser": "المتصفح", - "Broadcast_channel_Description": "يمكن فقط للمستخدمين المصرح لهم كتابة رسائل جديدة، ولكن سيتمكن المستخدمون الآخرون من الرد", - "Broadcast_Channel": "قناة البث", + "Broadcast_hint": "يمكن فقط للمستخدمين المصرح لهم كتابة رسائل جديدة، ولكن سيتمكن المستخدمون الآخرون من الرد", "Busy": "مشغول", "By_proceeding_you_are_agreeing": "من خلال المتابعة، أنت توافق على", "Cancel_editing": "إلغاء التعديل", @@ -389,7 +388,6 @@ "Preferences": "التفضيلات", "Preferences_saved": "تم حفظ التفضيلات", "Privacy_Policy": "سياسة الخصوصية", - "Private_Channel": "قناة خاصة", "Private": "خاص", "Processing": "جار معالجة...", "Profile_saved_successfully": "تم حفظ الملف الشخصي بنجاح!", @@ -403,7 +401,6 @@ "Reactions": "التفاعلات", "Read_External_Permission_Message": "يحتاج Rocket.chat للوصول إلى الصور والملفات الموجودة على الجهاز", "Read_External_Permission": "صلاحية قراءة الوسائط", - "Read_Only_Channel": "قناة للقراءة فقط", "Read_Only": "قراءة فقط", "Read_Receipt": "قراءة المستلم", "Receive_Group_Mentions": "تلقي إشارات المجموعة", diff --git a/app/i18n/locales/de.json b/app/i18n/locales/de.json index 17e7ad23e..11c5c34c5 100644 --- a/app/i18n/locales/de.json +++ b/app/i18n/locales/de.json @@ -119,8 +119,7 @@ "Black": "Schwarz", "Block_user": "Benutzer blockieren", "Browser": "Browser", - "Broadcast_channel_Description": "Nur autorisierte Benutzer können neue Nachrichten schreiben, die anderen Benutzer können jedoch antworten", - "Broadcast_Channel": "Broadcast-Kanal", + "Broadcast_hint": "Nur autorisierte Benutzer können neue Nachrichten schreiben, die anderen Benutzer können jedoch antworten", "Busy": "Beschäftigt", "By_proceeding_you_are_agreeing": "Indem Sie fortfahren, akzeptieren Sie unsere", "Cancel_editing": "Bearbeitung abbrechen", @@ -394,7 +393,6 @@ "Preferences": "Einstellungen", "Preferences_saved": "Einstellungen gespeichert!", "Privacy_Policy": " Datenschutzbestimmungen", - "Private_Channel": "Privater Kanal", "Private": "Privat", "Processing": "Bearbeite …", "Profile_saved_successfully": "Profil erfolgreich gespeichert!", @@ -409,7 +407,6 @@ "Reactions": "Reaktionen", "Read_External_Permission_Message": "Rocket.Chat benötigt Zugriff auf Ihre Fotos, Medien und Dateien auf Ihrem Gerät", "Read_External_Permission": "Lese-Zugriff auf Medien", - "Read_Only_Channel": "Nur-Lese-Kanal", "Read_Only": "Schreibgeschützt", "Read_Receipt": "Lesebestätigung", "Receive_Group_Mentions": "Gruppen-Benachrichtigungen erhalten", @@ -705,9 +702,6 @@ "Team_not_found": "Team nicht gefunden", "Create_Team": "Team erstellen", "Team_Name": "Team-Name", - "Private_Team": "Privates Team", - "Read_Only_Team": "Nur-Lesen-Team", - "Broadcast_Team": "Broadcast-Team", "creating_team": "Team erstellen", "team-name-already-exists": "Ein Team mit diesem Namen existiert bereits", "Add_Channel_to_Team": "Kanal zum Team hinzufügen", diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index 5f0c0c134..202a6bceb 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -126,8 +126,6 @@ "Black": "Black", "Block_user": "Block user", "Browser": "Browser", - "Broadcast_channel_Description": "Only authorized users can write new messages, but the other users will be able to reply", - "Broadcast_Channel": "Broadcast Channel", "Busy": "Busy", "By_proceeding_you_are_agreeing": "By proceeding you are agreeing to our", "Cancel_editing": "Cancel editing", @@ -408,7 +406,6 @@ "Preferences": "Preferences", "Preferences_saved": "Preferences saved!", "Privacy_Policy": " Privacy Policy", - "Private_Channel": "Private Channel", "Private": "Private", "Processing": "Processing...", "Profile_saved_successfully": "Profile saved successfully!", @@ -423,7 +420,6 @@ "Reactions": "Reactions", "Read_External_Permission_Message": "Rocket.Chat needs to access photos, media, and files on your device", "Read_External_Permission": "Read Media Permission", - "Read_Only_Channel": "Read Only Channel", "Read_Only": "Read Only", "Read_Receipt": "Read Receipt", "Receive_Group_Mentions": "Receive Group Mentions", @@ -726,9 +722,6 @@ "Team_not_found": "Team not found", "Create_Team": "Create Team", "Team_Name": "Team Name", - "Private_Team": "Private Team", - "Read_Only_Team": "Read Only Team", - "Broadcast_Team": "Broadcast Team", "creating_team": "creating team", "team-name-already-exists": "A team with that name already exists", "Add_Channel_to_Team": "Add Channel to Team", @@ -844,6 +837,25 @@ "totp-invalid": "Code or password invalid", "Close_Chat": "Close Chat", "Select_tags": "Select tags", + "Skip": "Skip", + "N_Selected_members": "{{n}} selected", + "Broadcast": "Broadcast", + "Broadcast_hint": "Only authorized users can write new messages, but the other users will be able to reply", + "Team_hint_private": "Only invited people can join", + "Team_hint_public": "When disabled, anyone can join the team", + "Team_hint_not_read_only": "All users in this team can write messages", + "Team_hint_encrypted": "End to end encrypted team. Search will not work with encrypted Teams and notifications may not show the messages content.", + "Team_hint_encrypted_not_available": "Only available for private team", + "Channel_hint_private":"Only invited users can access this Channel", + "Channel_hint_public":"Everyone can access this channel", + "Channel_hint_encrypted": "End to end encrypted channel. Search will not work with encrypted channels and notifications may not show the messages content.", + "Channel_hint_not_read_only": "All users in the channel can write new messages", + "Channel_hint_encrypted_not_available": "Not available for Public Channels", + "Read_only_hint":"Only authorized users can write new messages", + "Discussion": "Discussion", + "Channel": "Channel", + "Team": "Team", + "Select_Members": "Select Members", "Also_send_thread_message_to_channel_behavior": "Also send thread message to channel", "Accounts_Default_User_Preferences_alsoSendThreadToChannel_Description": "Allow users to select the Also send to channel behavior" } \ No newline at end of file diff --git a/app/i18n/locales/es-ES.json b/app/i18n/locales/es-ES.json index 81fa6194e..2a3e5bcf1 100644 --- a/app/i18n/locales/es-ES.json +++ b/app/i18n/locales/es-ES.json @@ -108,8 +108,7 @@ "Back": "Volver", "Black": "Negro", "Block_user": "Bloquear usuario", - "Broadcast_channel_Description": "Sólo los usuarios autorizados pueden escribir nuevos mensajes, el resto podrán responder sobre los mismos.", - "Broadcast_Channel": "Canal de Transmisión", + "Broadcast_hint": "Sólo los usuarios autorizados pueden escribir nuevos mensajes, el resto podrán responder sobre los mismos.", "Busy": "Ocupado", "By_proceeding_you_are_agreeing": "Al proceder estarás de acuerdo", "Cancel_editing": "Cancelar edición", @@ -273,7 +272,6 @@ "Preferences": "Preferencias", "Preferences_saved": "¡Preferencias guardadas!", "Privacy_Policy": "Política de privacidad", - "Private_Channel": "Canal privado", "Private": "Privado", "Processing": "Procesando...", "Profile_saved_successfully": "¡Perfil guardado correctamente!", @@ -286,7 +284,6 @@ "Reactions_are_disabled": "Las reacciones están desactivadas", "Reactions_are_enabled": "Las reacciones están activadas", "Reactions": "Reacciones", - "Read_Only_Channel": "Canal de sólo lectura", "Read_Only": "Sólo lectura ", "Read_Receipt": "Comprobante de lectura", "Receive_Group_Mentions": "Recibir menciones de grupo", diff --git a/app/i18n/locales/fr.json b/app/i18n/locales/fr.json index 62e128f49..b30d3ee5d 100644 --- a/app/i18n/locales/fr.json +++ b/app/i18n/locales/fr.json @@ -119,8 +119,7 @@ "Black": "Noir", "Block_user": "Bloquer l'utilisateur", "Browser": "Navigateur", - "Broadcast_channel_Description": "Seuls les utilisateurs autorisés peuvent écrire de nouveaux messages, mais les autres utilisateurs pourront répondre.", - "Broadcast_Channel": "Canal de diffusion", + "Broadcast_hint": "Seuls les utilisateurs autorisés peuvent écrire de nouveaux messages, mais les autres utilisateurs pourront répondre.", "Busy": "Occupé", "By_proceeding_you_are_agreeing": "En poursuivant, vous acceptez nos", "Cancel_editing": "Annuler la modification", @@ -398,7 +397,6 @@ "Preferences": "Préférences", "Preferences_saved": "Préférences sauvegardées !", "Privacy_Policy": " Politique de confidentialité", - "Private_Channel": "Canal privé", "Private": "Privé", "Processing": "Traitement...", "Profile_saved_successfully": "Profil enregistré avec succès !", @@ -413,7 +411,6 @@ "Reactions": "Réactions", "Read_External_Permission_Message": "Rocket.Chat doit accéder aux photos, aux médias et aux fichiers sur votre appareil", "Read_External_Permission": "Permission de lecture des fichiers", - "Read_Only_Channel": "Canal en lecture seule", "Read_Only": "Lecture seule", "Read_Receipt": "Accusé de réception", "Receive_Group_Mentions": "Recevoir des mentions de groupe", @@ -715,9 +712,6 @@ "Team_not_found": "Equipe non trouvée", "Create_Team": "Créer une équipe", "Team_Name": "Nom de l'équipe", - "Private_Team": "Equipe privée", - "Read_Only_Team": "Equipe en lecture seule", - "Broadcast_Team": "Equipe de diffusion", "creating_team": "création de l'équipe", "team-name-already-exists": "Une équipe portant ce nom existe déjà", "Add_Channel_to_Team": "Ajouter un canal à l'équipe", diff --git a/app/i18n/locales/it.json b/app/i18n/locales/it.json index 9617911ad..9792c34e8 100644 --- a/app/i18n/locales/it.json +++ b/app/i18n/locales/it.json @@ -115,8 +115,7 @@ "Black": "Nero", "Block_user": "Blocca utente", "Browser": "Browser", - "Broadcast_channel_Description": "Solo gli utenti autorizzati possono scrivere messaggi, ma gli altri utenti saranno in grado di rispondere", - "Broadcast_Channel": "Canale broadcast", + "Broadcast_hint": "Solo gli utenti autorizzati possono scrivere messaggi, ma gli altri utenti saranno in grado di rispondere", "Busy": "Occupato", "By_proceeding_you_are_agreeing": "Procedendo accetti i nostri", "Cancel_editing": "Annulla modifica", @@ -383,7 +382,6 @@ "Preferences": "Impostazioni", "Preferences_saved": "Impostazioni salvate!", "Privacy_Policy": " Privacy Policy", - "Private_Channel": "Canale privato", "Private": "Privato", "Processing": "Elaborazione...", "Profile_saved_successfully": "Profilo salvato correttamente!", @@ -398,7 +396,6 @@ "Reactions": "Reazioni", "Read_External_Permission_Message": "Rocket.Chat deve accedere alle foto, media, e documenti sul tuo dispositivo", "Read_External_Permission": "Permesso di Lettura della Memoria", - "Read_Only_Channel": "Canale in sola lettura", "Read_Only": "Sola lettura", "Read_Receipt": "Conferma di lettura", "Receive_Group_Mentions": "Ricevi menzioni di gruppo", diff --git a/app/i18n/locales/ja.json b/app/i18n/locales/ja.json index 1367a4be5..53c22c5cf 100644 --- a/app/i18n/locales/ja.json +++ b/app/i18n/locales/ja.json @@ -119,8 +119,7 @@ "Black": "ブラック", "Block_user": "ブロックしたユーザー", "Browser": "ブラウザ", - "Broadcast_channel_Description": "許可されたユーザーのみが新しいメッセージを書き込めます。他のユーザーは返信することができます", - "Broadcast_Channel": "配信チャンネル", + "Broadcast_hint": "許可されたユーザーのみが新しいメッセージを書き込めます。他のユーザーは返信することができます", "Busy": "取り込み中", "By_proceeding_you_are_agreeing": "続行することにより、私達を承認します", "Cancel_editing": "編集をキャンセル", @@ -371,7 +370,6 @@ "Preferences": "設定", "Preferences_saved": "設定が保存されました。", "Privacy_Policy": " プライバシーポリシー", - "Private_Channel": "プライベートチャンネル", "Private": "プライベート", "Processing": "処理中...", "Profile_saved_successfully": "プロフィールが保存されました!", @@ -384,7 +382,6 @@ "Reactions_are_disabled": "リアクションは無効化されています", "Reactions_are_enabled": "リアクションは有効化されています", "Reactions": "リアクション", - "Read_Only_Channel": "読み取り専用チャンネル", "Read_Only": "読み取り専用", "Read_Receipt": "レシートを見る", "Receive_Group_Mentions": "グループの通知を受け取る", diff --git a/app/i18n/locales/nl.json b/app/i18n/locales/nl.json index 141638baa..110c743fe 100644 --- a/app/i18n/locales/nl.json +++ b/app/i18n/locales/nl.json @@ -119,8 +119,7 @@ "Black": "Zwart", "Block_user": "Blokkeer gebruiker", "Browser": "Browser", - "Broadcast_channel_Description": "Alleen geautoriseerde gebruikers kunnen nieuwe berichten schrijven, maar de andere gebruikers zullen kunnen antwoorden", - "Broadcast_Channel": "Uitzendkanaal", + "Broadcast_hint": "Alleen geautoriseerde gebruikers kunnen nieuwe berichten schrijven, maar de andere gebruikers zullen kunnen antwoorden", "Busy": "Bezig", "By_proceeding_you_are_agreeing": "Door verder te gaan ga je akkoord met onze", "Cancel_editing": "Bewerken annuleren", @@ -398,7 +397,6 @@ "Preferences": "Voorkeuren", "Preferences_saved": "Voorkeuren opgeslagen!", "Privacy_Policy": " Privacybeleid", - "Private_Channel": "Privékanaal", "Private": "Privé", "Processing": "Verwerking...", "Profile_saved_successfully": "Profiel succesvol opgeslagen!", @@ -413,7 +411,6 @@ "Reactions": "Reacties", "Read_External_Permission_Message": "Rocket.Chat heeft toegang nodig tot foto's, media en bestanden op je apparaat", "Read_External_Permission": "Lees toestemming voor media", - "Read_Only_Channel": "Alleen-lezen kanaal", "Read_Only": "Alleen lezen", "Read_Receipt": "Leesbevestiging", "Receive_Group_Mentions": "Groepsvermeldingen ontvangen", @@ -715,9 +712,6 @@ "Team_not_found": "Team niet gevonden", "Create_Team": "Team aanmaken", "Team_Name": "Teamnaam", - "Private_Team": "Privé team", - "Read_Only_Team": "Alleen-lezen team", - "Broadcast_Team": "Broadcast team", "creating_team": "team maken", "team-name-already-exists": "Er bestaat al een team met die naam", "Add_Channel_to_Team": "Kanaal toevoegen aan team", diff --git a/app/i18n/locales/pt-BR.json b/app/i18n/locales/pt-BR.json index 694aef0d6..32c5617f1 100644 --- a/app/i18n/locales/pt-BR.json +++ b/app/i18n/locales/pt-BR.json @@ -121,8 +121,6 @@ "Black": "Preto", "Block_user": "Bloquear usuário", "Browser": "Navegador", - "Broadcast_channel_Description": "Somente usuários autorizados podem escrever novas mensagens, mas os outros usuários poderão responder", - "Broadcast_Channel": "Canal de Transmissão", "Busy": "Ocupado", "By_proceeding_you_are_agreeing": "Ao prosseguir você está aceitando", "Cancel_editing": "Cancelar edição", @@ -384,7 +382,6 @@ "Preferences": "Preferências", "Preferences_saved": "Preferências salvas!", "Privacy_Policy": " Política de Privacidade", - "Private_Channel": "Canal Privado", "Private": "Privado", "Processing": "Processando...", "Profile_saved_successfully": "Perfil salvo com sucesso!", @@ -399,7 +396,6 @@ "Reactions": "Reações", "Read_External_Permission_Message": "Rocket.Chat precisa acessar fotos, mídia e arquivos no seu dispositivo", "Read_External_Permission": "Permissão de acesso à arquivos", - "Read_Only_Channel": "Canal Somente Leitura", "Read_Only": "Somente Leitura", "Read_Receipt": "Lida por", "Receive_Group_Mentions": "Receber menções de grupo", @@ -683,7 +679,6 @@ "Teams": "Times", "No_team_channels_found": "Nenhum canal encontrado", "Team_not_found": "Time não encontrado", - "Private_Team": "Equipe Privada", "Add_Channel_to_Team": "Adicionar Canal ao Time", "Left_The_Team_Successfully": "Saiu do time com sucesso", "Create_New": "Criar", @@ -797,6 +792,25 @@ "totp-invalid": "Código ou senha inválida", "Close_Chat": "Fechar Conversa", "Select_tags": "Selecionar tag(s)", + "Skip": "Pular", + "N_Selected_members": "{{n}} selecionados", + "Broadcast": "Transmissão", + "Broadcast_hint": "Somente usuários autorizados podem escrever novas mensagens, mas os outros usuários poderão responder", + "Team_hint_private": "Apenas pessoas convidadas podem entrar", + "Team_hint_public": "Quando desativado, qualquer um pode entrar na equipe", + "Team_hint_not_read_only": "Todos os usuários nesta equipe podem escrever mensagens", + "Team_hint_encrypted": "Equipe criptografada de ponta a ponta. A pesquisa não funcionará com equipes criptografadas e as notificações poderão não exibir o conteúdo das mensagens.", + "Team_hint_encrypted_not_available": "Disponível apenas para equipes privadas", + "Channel_hint_private":"Apenas usuários convidados podem acessar este canal", + "Channel_hint_public":"Todos podem acessar este canal", + "Channel_hint_encrypted": "Canal criptografado de ponta a ponta. A pesquisa não funcionará com canais criptografados e as notificações podem não mostrar o conteúdo das mensagens.", + "Channel_hint_not_read_only": "Todos usuários no canal podem enviar mensagens novas", + "Channel_hint_encrypted_not_available": "Indisponível para canais públicos", + "Read_only_hint":"Somente usuários autorizados podem escrever novas mensagens", + "Discussion": "Discussão", + "Channel": "Canal", + "Team": "Time", + "Select_Members": "Selecionar Membros", "Also_send_thread_message_to_channel_behavior": "Também enviar mensagem do tópico para o canal", "Accounts_Default_User_Preferences_alsoSendThreadToChannel_Description": "Permitir que os usuários selecionem o comportamento Também enviar para o canal" } \ No newline at end of file diff --git a/app/i18n/locales/pt-PT.json b/app/i18n/locales/pt-PT.json index 9509842ec..fd6f3d5be 100644 --- a/app/i18n/locales/pt-PT.json +++ b/app/i18n/locales/pt-PT.json @@ -118,8 +118,7 @@ "Black": "Preto", "Block_user": "Bloquear utilizador", "Browser": "Navegador", - "Broadcast_channel_Description": "Apenas utilizadores autorizados podem escrever novas mensagens, mas os outros utilizadores poderão responder", - "Broadcast_Channel": "Canal de Transmissão", + "Broadcast_hint": "Apenas utilizadores autorizados podem escrever novas mensagens, mas os outros utilizadores poderão responder", "Busy": "Ocupado", "By_proceeding_you_are_agreeing": "Ao prosseguir você concorda com o(s) nosso(s)", "Cancel_editing": "Cancelar edição", @@ -390,7 +389,6 @@ "Preferences": "Preferências", "Preferences_saved": "Preferências guardadas!", "Privacy_Policy": " Política de Privacidade", - "Private_Channel": "Canal Privado", "Private": "Privado", "Processing": "A processar...", "Profile_saved_successfully": "Perfil actualizado com sucesso!", @@ -405,7 +403,6 @@ "Reactions": "Reacções", "Read_External_Permission_Message": "Rocket.Chat precisa acessar fotos, média e arquivos em seu dispositivo", "Read_External_Permission": "Permissão de leitura da média", - "Read_Only_Channel": "Canal só de leitura", "Read_Only": "Só de Leitura", "Read_Receipt": "Recibos de leitura", "Register": "Registar", diff --git a/app/i18n/locales/ru.json b/app/i18n/locales/ru.json index adb8923f6..01bbc8217 100644 --- a/app/i18n/locales/ru.json +++ b/app/i18n/locales/ru.json @@ -119,8 +119,7 @@ "Black": "Черный", "Block_user": "Блокировать пользователя", "Browser": "Браузер", - "Broadcast_channel_Description": "Только авторизованные пользователи могут писать новые сообщения, но другие пользователи смогут ответить", - "Broadcast_Channel": "Широковещательный канал", + "Broadcast_hint": "Только авторизованные пользователи могут писать новые сообщения, но другие пользователи смогут ответить", "Busy": "Занят", "By_proceeding_you_are_agreeing": "Продолжая, вы соглашаетесь с нашими", "Cancel_editing": "Отменить правку", @@ -394,7 +393,6 @@ "Preferences": "Настройки", "Preferences_saved": "Настройки сохранены!", "Privacy_Policy": " Политика конфиденциальности", - "Private_Channel": "Приватный канал", "Private": "Приватный", "Processing": "Обработка...", "Profile_saved_successfully": "Профиль успешно сохранен!", @@ -409,7 +407,6 @@ "Reactions": "Реакции", "Read_External_Permission_Message": "Rocket.Chat необходим доступ к фотографиям, медиа и другим файлам на вашем устройстве", "Read_External_Permission": "Разрешение на Чтение Медиа", - "Read_Only_Channel": "Канал только для чтения", "Read_Only": "Только для чтения", "Read_Receipt": "Уведомление о прочтении", "Receive_Group_Mentions": "Получать групповые уведомления", @@ -706,9 +703,6 @@ "Team_not_found": "Команда не найдена", "Create_Team": "Создать Команду", "Team_Name": "Имя Команды", - "Private_Team": "Приватная Команда", - "Read_Only_Team": "Команда только для чтения", - "Broadcast_Team": "Широковещательная Команда", "creating_team": "создание Команды", "team-name-already-exists": "Команда с таким названием уже существует", "Add_Channel_to_Team": "Добавить канал в Команду", diff --git a/app/i18n/locales/tr.json b/app/i18n/locales/tr.json index 092dbfda6..e8f26d3bf 100644 --- a/app/i18n/locales/tr.json +++ b/app/i18n/locales/tr.json @@ -115,8 +115,7 @@ "Black": "Koyu", "Block_user": "Kullanıcıyı engelle", "Browser": "Tarayıcı", - "Broadcast_channel_Description": "Yalnızca yetkili kullanıcılar yeni ileti yazabilir, ancak diğer kullanıcılar yanıt verebilir", - "Broadcast_Channel": "Kanala Yayınla", + "Broadcast_hint": "Yalnızca yetkili kullanıcılar yeni ileti yazabilir, ancak diğer kullanıcılar yanıt verebilir", "Busy": "Meşgul", "By_proceeding_you_are_agreeing": "Devam ederek kabul ediyorsunuz: ", "Cancel_editing": "Düzenlemeyi iptal et", @@ -384,7 +383,6 @@ "Preferences": "Tercihler", "Preferences_saved": "Tercihler kaydedildi!", "Privacy_Policy": " Privacy Policy", - "Private_Channel": "Özel Kanal", "Private": "Özel", "Processing": "İşleniyor...", "Profile_saved_successfully": "Profil başarıyla kaydedildi!", @@ -399,7 +397,6 @@ "Reactions": "Tepkiler", "Read_External_Permission_Message": "Rocket.Chat'in cihazınızdaki fotoğraflara, medyaya ve dosyalara erişmesi gerekiyor", "Read_External_Permission": "Medya Okuma İzni ", - "Read_Only_Channel": "Yazma Kısıtlı Kanal", "Read_Only": "Yazma Kısıtlı", "Read_Receipt": "Okundu Bilgisi", "Receive_Group_Mentions": "Grup Bahsetmelerini Al", diff --git a/app/i18n/locales/zh-CN.json b/app/i18n/locales/zh-CN.json index 119dfdf6c..6e6065347 100644 --- a/app/i18n/locales/zh-CN.json +++ b/app/i18n/locales/zh-CN.json @@ -115,8 +115,7 @@ "Black": "黑色", "Block_user": "屏蔽此用户", "Browser": "浏览器", - "Broadcast_channel_Description": "只有经过授权的用户才能写新信息,但其他用户可以回复", - "Broadcast_Channel": "广播频道", + "Broadcast_hint": "只有经过授权的用户才能写新信息,但其他用户可以回复", "Busy": "忙碌", "By_proceeding_you_are_agreeing": "继续操作,请同意我们的", "Cancel_editing": "取消编辑", @@ -381,7 +380,6 @@ "Preferences": "偏好设置", "Preferences_saved": "偏好已保存!", "Privacy_Policy": "隐私政策", - "Private_Channel": "私人频道", "Private": "私有的", "Processing": "处理中", "Profile_saved_successfully": "个人资料保存成功!", @@ -396,7 +394,6 @@ "Reactions": "表情貼", "Read_External_Permission_Message": "Rocket.Chat 需要存取您装置上的相片、多媒体及文件", "Read_External_Permission": "读取媒体权限", - "Read_Only_Channel": "只读频道", "Read_Only": "只读", "Read_Receipt": "查看已读人员", "Receive_Group_Mentions": "接收群组提及", diff --git a/app/i18n/locales/zh-TW.json b/app/i18n/locales/zh-TW.json index 4e8827ed6..bc9ea3b5c 100644 --- a/app/i18n/locales/zh-TW.json +++ b/app/i18n/locales/zh-TW.json @@ -116,8 +116,7 @@ "Black": "黑色", "Block_user": "封鎖此用戶", "Browser": "瀏覽器", - "Broadcast_channel_Description": "只有經過授權的使用者才能發送新訊息,但其他使用者可以回覆", - "Broadcast_Channel": "廣播頻道", + "Broadcast_hint": "只有經過授權的使用者才能發送新訊息,但其他使用者可以回覆", "Busy": "忙碌", "By_proceeding_you_are_agreeing": "若要繼續操作,請同意我們的", "Cancel_editing": "取消編輯", @@ -383,7 +382,6 @@ "Preferences": "偏好設定", "Preferences_saved": "偏好設定已被儲存!", "Privacy_Policy": "隱私政策", - "Private_Channel": "私人頻道", "Private": "私有的", "Processing": "處理中", "Profile_saved_successfully": "個人資料儲存成功!", @@ -398,7 +396,6 @@ "Reactions": "表情貼", "Read_External_Permission_Message": "Rocket.Chat 需要存取您裝置上的相片、多媒體及檔案", "Read_External_Permission": "讀取媒體權限", - "Read_Only_Channel": "唯讀頻道", "Read_Only": "唯讀", "Read_Receipt": "查看已讀人員", "Receive_Group_Mentions": "接收群組提及", diff --git a/app/stacks/InsideStack.tsx b/app/stacks/InsideStack.tsx index d5938cb58..4c7007bd8 100644 --- a/app/stacks/InsideStack.tsx +++ b/app/stacks/InsideStack.tsx @@ -123,7 +123,7 @@ const ChatsStackNavigator = () => { options={ThreadMessagesView.navigationOptions} /> - + { - + - + ); diff --git a/app/stacks/MasterDetailStack/index.tsx b/app/stacks/MasterDetailStack/index.tsx index 80b2637db..37fb43bd9 100644 --- a/app/stacks/MasterDetailStack/index.tsx +++ b/app/stacks/MasterDetailStack/index.tsx @@ -187,9 +187,9 @@ const ModalStackNavigator = React.memo(({ navigation }: INavigation) => { - + - + diff --git a/app/views/CreateChannelView.tsx b/app/views/CreateChannelView.tsx deleted file mode 100644 index 9c09c2d2b..000000000 --- a/app/views/CreateChannelView.tsx +++ /dev/null @@ -1,427 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import { FlatList, ScrollView, StyleSheet, Switch, Text, View, SwitchProps } from 'react-native'; -import { dequal } from 'dequal'; - -import * as List from '../containers/List'; -import { TextInput } from '../containers/TextInput'; -import { sendLoadingEvent } from '../containers/Loading'; -import { createChannelRequest } from '../actions/createChannel'; -import { removeUser } from '../actions/selectedUsers'; -import KeyboardView from '../containers/KeyboardView'; -import scrollPersistTaps from '../lib/methods/helpers/scrollPersistTaps'; -import I18n from '../i18n'; -import UserItem from '../containers/UserItem'; -import * as HeaderButton from '../containers/HeaderButton'; -import StatusBar from '../containers/StatusBar'; -import { SWITCH_TRACK_COLOR, themes } from '../lib/constants'; -import { withTheme } from '../theme'; -import { Review } from '../lib/methods/helpers/review'; -import { getUserSelector } from '../selectors/login'; -import { events, logEvent } from '../lib/methods/helpers/log'; -import SafeAreaView from '../containers/SafeAreaView'; -import sharedStyles from './Styles'; -import { ChatsStackParamList } from '../stacks/types'; -import { IApplicationState, IBaseScreen, IUser } from '../definitions'; -import { hasPermission } from '../lib/methods/helpers'; - -const styles = StyleSheet.create({ - container: { - flex: 1 - }, - list: { - width: '100%' - }, - input: { - height: 54, - paddingHorizontal: 18, - fontSize: 17, - ...sharedStyles.textRegular - }, - switchContainer: { - height: 54, - alignItems: 'center', - justifyContent: 'space-between', - flexDirection: 'row', - paddingHorizontal: 18 - }, - label: { - fontSize: 17, - ...sharedStyles.textMedium - }, - invitedHeader: { - marginTop: 18, - marginHorizontal: 15, - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center' - }, - invitedTitle: { - fontSize: 18, - ...sharedStyles.textSemibold, - lineHeight: 41 - }, - invitedCount: { - fontSize: 14, - ...sharedStyles.textRegular - } -}); - -interface IOtherUser { - _id: string; - name: string; - fname: string; -} - -interface ICreateChannelViewState { - channelName: string; - type: boolean; - readOnly: boolean; - encrypted: boolean; - broadcast: boolean; - isTeam: boolean; - permissions: boolean[]; -} - -interface ICreateChannelViewProps extends IBaseScreen { - baseUrl: string; - error: object; - failure: boolean; - isFetching: boolean; - encryptionEnabled: boolean; - users: IOtherUser[]; - user: IUser; - teamId: string; - createPublicChannelPermission: string[] | undefined; - createPrivateChannelPermission: string[] | undefined; -} - -interface ISwitch extends SwitchProps { - id: string; - label: string; -} - -class CreateChannelView extends React.Component { - private teamId?: string; - - constructor(props: ICreateChannelViewProps) { - super(props); - const { route } = this.props; - const isTeam = route?.params?.isTeam || false; - this.teamId = route?.params?.teamId; - this.state = { - channelName: '', - type: true, - readOnly: false, - encrypted: false, - broadcast: false, - isTeam, - permissions: [] - }; - this.setHeader(); - } - - componentDidMount() { - this.handleHasPermission(); - } - - shouldComponentUpdate(nextProps: ICreateChannelViewProps, nextState: ICreateChannelViewState) { - const { channelName, type, readOnly, broadcast, encrypted, permissions } = this.state; - const { users, isFetching, encryptionEnabled, theme, createPublicChannelPermission, createPrivateChannelPermission } = - this.props; - if (nextProps.theme !== theme) { - return true; - } - if (nextState.channelName !== channelName) { - return true; - } - if (nextState.type !== type) { - return true; - } - if (nextState.readOnly !== readOnly) { - return true; - } - if (nextState.encrypted !== encrypted) { - return true; - } - if (nextState.broadcast !== broadcast) { - return true; - } - if (nextState.permissions !== permissions) { - return true; - } - if (nextProps.isFetching !== isFetching) { - return true; - } - if (nextProps.encryptionEnabled !== encryptionEnabled) { - return true; - } - if (!dequal(nextProps.createPublicChannelPermission, createPublicChannelPermission)) { - return true; - } - if (!dequal(nextProps.createPrivateChannelPermission, createPrivateChannelPermission)) { - return true; - } - if (!dequal(nextProps.users, users)) { - return true; - } - return false; - } - - componentDidUpdate(prevProps: ICreateChannelViewProps) { - const { createPublicChannelPermission, createPrivateChannelPermission, isFetching } = this.props; - if ( - !dequal(createPublicChannelPermission, prevProps.createPublicChannelPermission) || - !dequal(createPrivateChannelPermission, prevProps.createPrivateChannelPermission) - ) { - this.handleHasPermission(); - } - if (isFetching !== prevProps.isFetching) { - sendLoadingEvent({ visible: isFetching }); - } - } - - setHeader = () => { - const { navigation } = this.props; - const { isTeam } = this.state; - - navigation.setOptions({ - title: isTeam ? I18n.t('Create_Team') : I18n.t('Create_Channel') - }); - }; - - toggleRightButton = (channelName: string) => { - const { navigation } = this.props; - navigation.setOptions({ - headerRight: () => - channelName.trim().length > 0 && ( - - - - ) - }); - }; - - onChangeText = (channelName: string) => { - this.toggleRightButton(channelName); - this.setState({ channelName }); - }; - - submit = () => { - const { channelName, type, readOnly, broadcast, encrypted, isTeam } = this.state; - const { users: usersProps, isFetching, dispatch } = this.props; - - if (!channelName.trim() || isFetching) { - return; - } - - // transform users object into array of usernames - const users = usersProps.map(user => user.name); - - // create channel or team - const data = { - name: channelName, - users, - type, - readOnly, - broadcast, - encrypted, - isTeam, - teamId: this.teamId - }; - dispatch(createChannelRequest(data)); - Review.pushPositiveEvent(); - }; - - removeUser = (user: IOtherUser) => { - logEvent(events.CR_REMOVE_USER); - const { dispatch } = this.props; - dispatch(removeUser(user)); - }; - - renderSwitch = ({ id, value, label, onValueChange, disabled = false }: ISwitch) => { - const { theme } = this.props; - return ( - - {I18n.t(label)} - - - ); - }; - - handleHasPermission = async () => { - const { createPublicChannelPermission, createPrivateChannelPermission } = this.props; - const permissions = [createPublicChannelPermission, createPrivateChannelPermission]; - const permissionsToCreate = await hasPermission(permissions); - this.setState({ permissions: permissionsToCreate }); - }; - - renderType() { - const { type, isTeam, permissions } = this.state; - const isDisabled = permissions.filter(r => r === true).length <= 1; - - return this.renderSwitch({ - id: 'type', - value: permissions[1] ? type : false, - disabled: isDisabled, - label: isTeam ? 'Private_Team' : 'Private_Channel', - onValueChange: (value: boolean) => { - logEvent(events.CR_TOGGLE_TYPE); - // If we set the channel as public, encrypted status should be false - this.setState(({ encrypted }) => ({ type: value, encrypted: value && encrypted })); - } - }); - } - - renderReadOnly() { - const { readOnly, broadcast, isTeam } = this.state; - - return this.renderSwitch({ - id: 'readonly', - value: readOnly, - label: isTeam ? 'Read_Only_Team' : 'Read_Only_Channel', - onValueChange: value => { - logEvent(events.CR_TOGGLE_READ_ONLY); - this.setState({ readOnly: value }); - }, - disabled: broadcast - }); - } - - renderEncrypted() { - const { type, encrypted } = this.state; - const { encryptionEnabled } = this.props; - - if (!encryptionEnabled) { - return null; - } - - return this.renderSwitch({ - id: 'encrypted', - value: encrypted, - label: 'Encrypted', - onValueChange: value => { - logEvent(events.CR_TOGGLE_ENCRYPTED); - this.setState({ encrypted: value }); - }, - disabled: !type - }); - } - - renderBroadcast() { - const { broadcast, readOnly, isTeam } = this.state; - - return this.renderSwitch({ - id: 'broadcast', - value: broadcast, - label: isTeam ? 'Broadcast_Team' : 'Broadcast_Channel', - onValueChange: value => { - logEvent(events.CR_TOGGLE_BROADCAST); - this.setState({ - broadcast: value, - readOnly: value ? true : readOnly - }); - } - }); - } - - renderItem = ({ item }: { item: IOtherUser }) => ( - this.removeUser(item)} - testID={`create-channel-view-item-${item.name}`} - icon='check' - /> - ); - - renderInvitedList = () => { - const { users, theme } = this.props; - - return ( - item._id} - style={[ - styles.list, - sharedStyles.separatorVertical, - { - backgroundColor: themes[theme].focusedBackground, - borderColor: themes[theme].separatorColor - } - ]} - renderItem={this.renderItem} - ItemSeparatorComponent={List.Separator} - keyboardShouldPersistTaps='always' - /> - ); - }; - - render() { - const { channelName, isTeam } = this.state; - const { users, theme } = this.props; - const userCount = users.length; - - return ( - - - - - - - - {this.renderType()} - - {this.renderReadOnly()} - - {this.renderEncrypted()} - - {this.renderBroadcast()} - - - {I18n.t('Invite')} - - {userCount === 1 ? I18n.t('1_user') : I18n.t('N_users', { n: userCount })} - - - {this.renderInvitedList()} - - - - ); - } -} - -const mapStateToProps = (state: IApplicationState) => ({ - baseUrl: state.server.server, - isFetching: state.createChannel.isFetching, - encryptionEnabled: state.encryption.enabled, - users: state.selectedUsers.users, - user: getUserSelector(state), - createPublicChannelPermission: state.permissions['create-c'], - createPrivateChannelPermission: state.permissions['create-p'] -}); - -export default connect(mapStateToProps)(withTheme(CreateChannelView)); diff --git a/app/views/CreateChannelView/RoomSettings/SwitchItem.stories.tsx b/app/views/CreateChannelView/RoomSettings/SwitchItem.stories.tsx new file mode 100644 index 000000000..09aa2bc2c --- /dev/null +++ b/app/views/CreateChannelView/RoomSettings/SwitchItem.stories.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { View, StyleSheet } from 'react-native'; + +import { SwitchItem } from './SwitchItem'; + +const styles = StyleSheet.create({ + container: { + flex: 1, + alignItems: 'flex-start', + padding: 16 + } +}); + +export default { + title: 'SwitchItem' +}; + +const testSwitch = { + id: 'switch-id', + hint: 'Read_only_hint', + label: 'Onboarding_title', + onValueChange: () => {}, + value: false, + testSwitchID: 'create-channel-switch-id', + testLabelID: 'create-channel-switch-id-hint' +}; + +export const Switch = () => ( + <> + + testSwitch.onValueChange()} + value={testSwitch.value} + /> + + +); diff --git a/app/views/CreateChannelView/RoomSettings/SwitchItem.test.tsx b/app/views/CreateChannelView/RoomSettings/SwitchItem.test.tsx new file mode 100644 index 000000000..fa1fc6846 --- /dev/null +++ b/app/views/CreateChannelView/RoomSettings/SwitchItem.test.tsx @@ -0,0 +1,68 @@ +import React from 'react'; +import { fireEvent, render } from '@testing-library/react-native'; +import { Provider } from 'react-redux'; + +import i18n from '../../../i18n'; +import { SwitchItem, ISwitch } from './SwitchItem'; +import { mockedStore as store } from '../../../reducers/mockedStore'; + +const onPressMock = jest.fn((value: boolean) => value); + +const testSwitch = { + id: 'switch-id', + hint: 'Read_only_hint', + label: 'Onboarding_title', + onValueChange: onPressMock, + value: false, + testSwitchID: 'create-channel-switch-id', + testLabelID: 'create-channel-switch-id-hint' +}; + +const Render = ({ hint, id, label, onValueChange, value }: ISwitch) => ( + + + +); + +describe('SwitchItemEncrypted', () => { + it('should not render the Encrypted Switch component', async () => { + const { findByTestId } = render( + testSwitch.onValueChange(value)} + value={testSwitch.value} + /> + ); + const component = await findByTestId(testSwitch.testSwitchID); + expect(component).toBeTruthy(); + }); + it('should change value of switch', async () => { + const { findByTestId } = render( + testSwitch.onValueChange(value)} + value={testSwitch.value} + /> + ); + const component = await findByTestId(testSwitch.testSwitchID); + fireEvent(component, 'valueChange', { value: true }); + expect(onPressMock).toHaveReturnedWith({ value: !testSwitch.value }); + }); + it('check if hint exists and is the same from testSwitch object', async () => { + const { findByTestId } = render( + testSwitch.onValueChange(value)} + value={testSwitch.value} + /> + ); + const component = await findByTestId(testSwitch.testLabelID); + expect(component.props.children).toBe(i18n.t(testSwitch.hint)); + }); +}); diff --git a/app/views/CreateChannelView/RoomSettings/SwitchItem.tsx b/app/views/CreateChannelView/RoomSettings/SwitchItem.tsx new file mode 100644 index 000000000..4e8b548e3 --- /dev/null +++ b/app/views/CreateChannelView/RoomSettings/SwitchItem.tsx @@ -0,0 +1,59 @@ +import React from 'react'; +import { StyleSheet, Switch, Text, View, SwitchProps } from 'react-native'; + +import I18n from '../../../i18n'; +import { SWITCH_TRACK_COLOR } from '../../../lib/constants'; +import { useTheme } from '../../../theme'; +import sharedStyles from '../../Styles'; + +const styles = StyleSheet.create({ + switchContainer: { + minHeight: 54, + alignItems: 'center', + justifyContent: 'space-between', + flexDirection: 'row', + maxHeight: 80, + marginBottom: 12 + }, + switchTextContainer: { + flex: 1, + marginRight: 8 + }, + label: { + fontSize: 14, + ...sharedStyles.textMedium + }, + hint: { + fontSize: 14, + ...sharedStyles.textRegular + } +}); + +export interface ISwitch extends SwitchProps { + id: string; + label: string; + hint: string; + onValueChange: (value: boolean) => void; +} + +export const SwitchItem = ({ id, value, label, hint, onValueChange, disabled = false }: ISwitch) => { + const { colors } = useTheme(); + + return ( + + + {I18n.t(label)} + + {I18n.t(hint)} + + + + + ); +}; diff --git a/app/views/CreateChannelView/RoomSettings/SwitchItemEncrypted.test.tsx b/app/views/CreateChannelView/RoomSettings/SwitchItemEncrypted.test.tsx new file mode 100644 index 000000000..f6705b505 --- /dev/null +++ b/app/views/CreateChannelView/RoomSettings/SwitchItemEncrypted.test.tsx @@ -0,0 +1,108 @@ +import React from 'react'; +import { fireEvent, render } from '@testing-library/react-native'; +import { Provider } from 'react-redux'; + +import { SwitchItemEncrypted, ISwitchItemEncrypted } from './SwitchItemEncrypted'; +import { mockedStore as store } from '../../../reducers/mockedStore'; +import i18n from '../../../i18n'; + +const onPressMock = jest.fn((value: boolean) => value); + +const testEncrypted = { + encrypted: false, + encryptionEnabled: false, + isTeam: false, + onValueChangeEncrypted: onPressMock, + type: false, + testSwitchID: 'create-channel-encrypted', + testLabelID: `create-channel-encrypted-hint` +}; + +const Render = ({ encrypted, encryptionEnabled, isTeam, onValueChangeEncrypted, type }: ISwitchItemEncrypted) => ( + + + +); + +describe('SwitchItemEncrypted', () => { + it('should not render the Encrypted Switch component', async () => { + const { findByTestId } = render( + testEncrypted.onValueChangeEncrypted(value)} + type={testEncrypted.type} + /> + ); + try { + await findByTestId(testEncrypted.testSwitchID); + } catch (e) { + expect(e).toBeTruthy(); + } + }); + it('should render the Encrypted Switch component', async () => { + testEncrypted.encryptionEnabled = true; + const { findByTestId } = render( + testEncrypted.onValueChangeEncrypted(value)} + type={testEncrypted.type} + /> + ); + const component = await findByTestId(testEncrypted.testSwitchID); + expect(component).toBeTruthy(); + }); + it('should change value of switch', async () => { + const { findByTestId } = render( + testEncrypted.onValueChangeEncrypted(value)} + type={testEncrypted.type} + /> + ); + + const component = await findByTestId(testEncrypted.testSwitchID); + fireEvent(component, 'valueChange', { value: true }); + expect(onPressMock).toHaveReturnedWith({ value: !testEncrypted.encrypted }); + }); + it('label when encrypted and isTeam are false and is a public channel', async () => { + const { findByTestId } = render( + testEncrypted.onValueChangeEncrypted(value)} + type={testEncrypted.type} + /> + ); + const component = await findByTestId(testEncrypted.testLabelID); + expect(component.props.children).toBe(i18n.t('Channel_hint_encrypted_not_available')); + }); + it('label when encrypted and isTeam are true and is a private team', async () => { + testEncrypted.isTeam = true; + testEncrypted.type = true; + testEncrypted.encrypted = true; + const { findByTestId } = render( + testEncrypted.onValueChangeEncrypted(value)} + type={testEncrypted.type} + /> + ); + const component = await findByTestId(testEncrypted.testLabelID); + expect(component.props.children).toBe(i18n.t('Team_hint_encrypted')); + }); +}); diff --git a/app/views/CreateChannelView/RoomSettings/SwitchItemEncrypted.tsx b/app/views/CreateChannelView/RoomSettings/SwitchItemEncrypted.tsx new file mode 100644 index 000000000..9cc277c65 --- /dev/null +++ b/app/views/CreateChannelView/RoomSettings/SwitchItemEncrypted.tsx @@ -0,0 +1,48 @@ +import React from 'react'; + +import { SwitchItem } from './SwitchItem'; + +export interface ISwitchItemEncrypted { + encryptionEnabled: boolean; + isTeam: boolean; + type: boolean; + encrypted: boolean; + onValueChangeEncrypted: (value: boolean) => void; +} + +export const SwitchItemEncrypted = ({ + encryptionEnabled, + isTeam, + type, + encrypted, + onValueChangeEncrypted +}: ISwitchItemEncrypted) => { + if (!encryptionEnabled) { + return null; + } + + let hint = ''; + if (isTeam && type) { + hint = 'Team_hint_encrypted'; + } + if (isTeam && !type) { + hint = 'Team_hint_encrypted_not_available'; + } + if (!isTeam && type) { + hint = 'Channel_hint_encrypted'; + } + if (!isTeam && !type) { + hint = 'Channel_hint_encrypted_not_available'; + } + + return ( + + ); +}; diff --git a/app/views/CreateChannelView/RoomSettings/SwitchItemReadOnly.tsx b/app/views/CreateChannelView/RoomSettings/SwitchItemReadOnly.tsx new file mode 100644 index 000000000..7711879cc --- /dev/null +++ b/app/views/CreateChannelView/RoomSettings/SwitchItemReadOnly.tsx @@ -0,0 +1,37 @@ +import React from 'react'; + +import { SwitchItem } from './SwitchItem'; + +export const SwitchItemReadOnly = ({ + readOnly, + isTeam, + onValueChangeReadOnly, + broadcast +}: { + readOnly: boolean; + isTeam: boolean; + onValueChangeReadOnly: (value: boolean) => void; + broadcast: boolean; +}) => { + let hint = ''; + if (readOnly) { + hint = 'Read_only_hint'; + } + if (isTeam && !readOnly) { + hint = 'Team_hint_not_read_only'; + } + if (!isTeam && !readOnly) { + hint = 'Channel_hint_not_read_only'; + } + + return ( + + ); +}; diff --git a/app/views/CreateChannelView/RoomSettings/SwitchItemType.tsx b/app/views/CreateChannelView/RoomSettings/SwitchItemType.tsx new file mode 100644 index 000000000..6299dec97 --- /dev/null +++ b/app/views/CreateChannelView/RoomSettings/SwitchItemType.tsx @@ -0,0 +1,43 @@ +import React from 'react'; + +import { usePermissions } from '../../../lib/hooks'; +import { SwitchItem } from './SwitchItem'; + +export const SwitchItemType = ({ + isTeam, + type, + onValueChangeType +}: { + isTeam: boolean; + type: boolean; + onValueChangeType: (value: boolean) => void; +}) => { + const [createChannelPermission, createPrivateChannelPermission] = usePermissions(['create-c', 'create-p']); + + const isDisabled = [createChannelPermission, createPrivateChannelPermission].filter(r => r === true).length <= 1; + + let hint = ''; + if (isTeam && type) { + hint = 'Team_hint_private'; + } + if (isTeam && !type) { + hint = 'Team_hint_public'; + } + if (!isTeam && type) { + hint = 'Channel_hint_private'; + } + if (!isTeam && !type) { + hint = 'Channel_hint_public'; + } + + return ( + + ); +}; diff --git a/app/views/CreateChannelView/RoomSettings/index.tsx b/app/views/CreateChannelView/RoomSettings/index.tsx new file mode 100644 index 000000000..5d27ca1e0 --- /dev/null +++ b/app/views/CreateChannelView/RoomSettings/index.tsx @@ -0,0 +1,78 @@ +import React, { useCallback, useState } from 'react'; +import { UseFormSetValue } from 'react-hook-form'; + +import { useAppSelector } from '../../../lib/hooks'; +import { events, logEvent } from '../../../lib/methods/helpers/log'; +import { SwitchItem } from './SwitchItem'; +import { SwitchItemType } from './SwitchItemType'; +import { SwitchItemReadOnly } from './SwitchItemReadOnly'; +import { SwitchItemEncrypted } from './SwitchItemEncrypted'; +import { IFormData } from '..'; + +export const RoomSettings = ({ isTeam, setValue }: { isTeam: boolean; setValue: UseFormSetValue }) => { + const [type, setType] = useState(true); + const [readOnly, setReadOnly] = useState(false); + const [encrypted, setEncrypted] = useState(false); + const [broadcast, setBroadcast] = useState(false); + + const { encryptionEnabled } = useAppSelector(state => ({ + encryptionEnabled: state.encryption.enabled + })); + + const onValueChangeType = useCallback( + (value: boolean) => { + logEvent(events.CR_TOGGLE_TYPE); + // If we set the channel as public, encrypted status should be false + setType(value); + setValue('type', value); + setEncrypted(value && encrypted); + setValue('encrypted', value && encrypted); + }, + [encrypted] + ); + + const onValueChangeReadOnly = useCallback((value: boolean) => { + logEvent(events.CR_TOGGLE_READ_ONLY); + setReadOnly(value); + setValue('readOnly', value); + }, []); + + const onValueChangeEncrypted = useCallback((value: boolean) => { + logEvent(events.CR_TOGGLE_ENCRYPTED); + setEncrypted(value); + setValue('encrypted', value); + }, []); + + const onValueChangeBroadcast = (value: boolean) => { + logEvent(events.CR_TOGGLE_BROADCAST); + setBroadcast(value); + setValue('broadcast', value); + setReadOnly(value ? true : readOnly); + setValue('readOnly', value ? true : readOnly); + }; + return ( + <> + + + + + + ); +}; diff --git a/app/views/CreateChannelView/index.tsx b/app/views/CreateChannelView/index.tsx new file mode 100644 index 000000000..be02e0d9f --- /dev/null +++ b/app/views/CreateChannelView/index.tsx @@ -0,0 +1,205 @@ +import React, { useCallback, useEffect, useLayoutEffect } from 'react'; +import { shallowEqual, useDispatch } from 'react-redux'; +import { FlatList, ScrollView, StyleSheet, Text, View } from 'react-native'; +import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; +import { useForm } from 'react-hook-form'; + +import { useAppSelector } from '../../lib/hooks'; +import { sendLoadingEvent } from '../../containers/Loading'; +import { createChannelRequest } from '../../actions/createChannel'; +import { removeUser as removeUserAction } from '../../actions/selectedUsers'; +import KeyboardView from '../../containers/KeyboardView'; +import scrollPersistTaps from '../../lib/methods/helpers/scrollPersistTaps'; +import I18n from '../../i18n'; +import StatusBar from '../../containers/StatusBar'; +import { useTheme } from '../../theme'; +import { Review } from '../../lib/methods/helpers/review'; +import SafeAreaView from '../../containers/SafeAreaView'; +import sharedStyles from '../Styles'; +import { ChatsStackParamList } from '../../stacks/types'; +import Button from '../../containers/Button'; +import { ControlledFormTextInput } from '../../containers/TextInput'; +import Chip from '../../containers/Chip'; +import { RoomSettings } from './RoomSettings'; +import { ISelectedUser } from '../../reducers/selectedUsers'; + +const styles = StyleSheet.create({ + container: { + flex: 1 + }, + containerTextInput: { + paddingHorizontal: 16, + marginTop: 16 + }, + containerStyle: { + marginBottom: 28 + }, + list: { + width: '100%' + }, + invitedHeader: { + marginVertical: 12, + marginHorizontal: 16, + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center' + }, + invitedCount: { + fontSize: 12, + ...sharedStyles.textRegular + }, + invitedList: { + paddingHorizontal: 16 + }, + buttonCreate: { + marginHorizontal: 16, + marginTop: 24 + } +}); + +export interface IFormData { + channelName: string; + type: boolean; + readOnly: boolean; + encrypted: boolean; + broadcast: boolean; +} + +const CreateChannelView = () => { + const { + control, + handleSubmit, + formState: { isDirty }, + setValue + } = useForm({ + defaultValues: { channelName: '', broadcast: false, encrypted: false, readOnly: false, type: false } + }); + + const navigation = useNavigation>(); + const { params } = useRoute>(); + const isTeam = params?.isTeam || false; + const teamId = params?.teamId; + const { colors } = useTheme(); + const dispatch = useDispatch(); + + const { isFetching, useRealName, users } = useAppSelector( + state => ({ + isFetching: state.createChannel.isFetching, + users: state.selectedUsers.users, + useRealName: state.settings.UI_Use_Real_Name as boolean + }), + shallowEqual + ); + + useEffect(() => { + sendLoadingEvent({ visible: isFetching }); + }, [isFetching]); + + useLayoutEffect(() => { + navigation.setOptions({ + title: isTeam ? I18n.t('Create_Team') : I18n.t('Create_Channel') + }); + }, [isTeam, navigation]); + + const removeUser = useCallback( + (user: ISelectedUser) => { + dispatch(removeUserAction(user)); + }, + [dispatch] + ); + + const submit = ({ channelName, broadcast, encrypted, readOnly, type }: IFormData) => { + if (!channelName.trim() || isFetching) { + return; + } + // transform users object into array of usernames + const usersMapped = users.map(user => user.name); + // create channel or team + const data = { + name: channelName, + users: usersMapped, + type, + readOnly, + broadcast, + encrypted, + isTeam, + teamId + }; + dispatch(createChannelRequest(data)); + Review.pushPositiveEvent(); + }; + + return ( + + + + + + + + + {users.length > 0 ? ( + <> + + + {I18n.t('N_Selected_members', { n: users.length })} + + + item._id} + style={[ + styles.list, + { + backgroundColor: colors.backgroundColor, + borderColor: colors.separatorColor + } + ]} + contentContainerStyle={styles.invitedList} + renderItem={({ item }) => { + const name = useRealName && item.fname ? item.fname : item.name; + const username = item.name; + + return ( + removeUser(item)} + testID={`create-channel-view-item-${item.name}`} + /> + ); + }} + keyboardShouldPersistTaps='always' + horizontal + /> + + ) : null} +