Skip to content

Commit

Permalink
[IMPROVE] Redesign create room flow (#4381)
Browse files Browse the repository at this point in the history
Co-authored-by: Diego Mello <[email protected]>
  • Loading branch information
reinaldonetof and diegolmello authored Aug 26, 2022
1 parent cbc6892 commit 9cbffff
Show file tree
Hide file tree
Showing 54 changed files with 1,532 additions and 1,167 deletions.
2 changes: 2 additions & 0 deletions .storybook/storybook.requires.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand All @@ -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"),
Expand Down
11 changes: 11 additions & 0 deletions __tests__/containers/Chip/__snapshots__/Chip.stories.storyshot
Original file line number Diff line number Diff line change
@@ -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\\"]}]}]}]}]}"`;
Original file line number Diff line number Diff line change
@@ -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}]}]}"`;
32 changes: 32 additions & 0 deletions app/containers/Chip/Chip.stories.tsx
Original file line number Diff line number Diff line change
@@ -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) => (
<View style={styles.container}>
<Chip avatar={avatar} text={text} onPress={onPress} testID={testID} style={style} />
</View>
);

export const ChipText = () => <ChipWrapped avatar='rocket.cat' text={'Rocket.Cat'} onPress={() => {}} />;

export const ChipWithShortText = () => <ChipWrapped avatar='rocket.cat' text={'Short'} onPress={() => {}} />;

export const ChipWithoutAvatar = () => <ChipWrapped text={'Without Avatar'} onPress={() => {}} />;

export const ChipWithoutIcon = () => <ChipWrapped avatar='rocket.cat' text='Without Icon' />;

export const ChipWithoutAvatarAndIcon = () => <ChipWrapped text='Without Avatar and Icon' />;
58 changes: 58 additions & 0 deletions app/containers/Chip/Chip.test.tsx
Original file line number Diff line number Diff line change
@@ -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) => (
<Provider store={store}>
<Chip testID={testID} text={text} onPress={onPress} avatar={avatar} />
</Provider>
);

describe('Chips', () => {
it('should render the Chip component', () => {
const { findByTestId } = render(
<Render
text={testChip.item.fname}
avatar={testChip.item.name}
testID={testChip.testID}
onPress={() => testChip.onPress(testChip.item)}
/>
);

expect(findByTestId(testChip.testID)).toBeTruthy();
});
it("should not call onPress if it's not passed", async () => {
const { findByTestId } = render(<Render text={testChip.item.fname} avatar={testChip.item.name} testID={testChip.testID} />);

const component = await findByTestId(testChip.testID);
fireEvent.press(component);
expect(onPressMock).not.toHaveBeenCalled();
});
it('should tap Chip and return item', async () => {
const { findByTestId } = render(
<Render
text={testChip.item.fname}
avatar={testChip.item.name}
testID={testChip.testID}
onPress={() => testChip.onPress(testChip.item)}
/>
);

const component = await findByTestId(testChip.testID);
fireEvent.press(component);
expect(onPressMock).toHaveBeenCalled();
expect(onPressMock).toHaveReturnedWith(testChip.item);
});
});
75 changes: 75 additions & 0 deletions app/containers/Chip/index.tsx
Original file line number Diff line number Diff line change
@@ -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<ViewStyle>;
}

const Chip = ({ avatar, text, onPress, testID, style }: IChip) => {
const { colors } = useTheme();

return (
<Pressable
testID={testID}
style={({ pressed }) => [
styles.pressable,
{
backgroundColor: pressed ? colors.bannerBackground : colors.auxiliaryBackground
},
style
]}
disabled={!onPress}
onPress={() => onPress?.()}
android_ripple={{
color: colors.bannerBackground
}}
>
<View style={styles.container}>
{avatar ? <Avatar text={avatar} size={28} style={styles.avatar} /> : null}
<View style={styles.textContainer}>
<Text style={[styles.name, { color: colors.bodyText }]} numberOfLines={1}>
{text}
</Text>
</View>
{onPress ? <CustomIcon name='close' size={16} color={colors.auxiliaryTintColor} /> : null}
</View>
</Pressable>
);
};

export default Chip;
17 changes: 17 additions & 0 deletions app/containers/TextInput/ControlledFormTextInput.tsx
Original file line number Diff line number Diff line change
@@ -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<any>;
name: string;
}

export const ControlledFormTextInput = ({ control, name, ...props }: IControlledFormTextInputProps) => (
<Controller
control={control}
name={name}
render={({ field: { onChange, value } }) => <FormTextInput onChangeText={onChange} value={value} {...props} />}
/>
);
1 change: 1 addition & 0 deletions app/containers/TextInput/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './TextInput';
export * from './FormTextInput';
export * from './ControlledFormTextInput';
17 changes: 6 additions & 11 deletions app/containers/UserItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -46,10 +42,12 @@ interface IUserItem {
onLongPress?: () => void;
style?: StyleProp<ViewStyle>;
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 (
<Pressable
onPress={onPress}
Expand All @@ -65,14 +63,11 @@ const UserItem = ({ name, username, onPress, testID, onLongPress, style, icon }:
<View style={[styles.container, styles.button, style]}>
<Avatar text={username} size={30} style={styles.avatar} />
<View style={styles.textContainer}>
<Text style={[styles.name, { color: colors.titleText }]} numberOfLines={1}>
<Text style={[styles.name, { color: colors.bodyText }]} numberOfLines={1}>
{name}
</Text>
<Text style={[styles.username, { color: colors.auxiliaryText }]} numberOfLines={1}>
@{username}
</Text>
</View>
{icon ? <CustomIcon name={icon} size={22} color={colors.actionTintColor} style={styles.icon} /> : null}
{icon ? <CustomIcon name={icon} size={22} color={iconColor || colors.actionTintColor} style={styles.icon} /> : null}
</View>
</Pressable>
);
Expand Down
5 changes: 1 addition & 4 deletions app/i18n/locales/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,7 @@
"Black": "أسود",
"Block_user": "حظر المستخدم",
"Browser": "المتصفح",
"Broadcast_channel_Description": "يمكن فقط للمستخدمين المصرح لهم كتابة رسائل جديدة، ولكن سيتمكن المستخدمون الآخرون من الرد",
"Broadcast_Channel": "قناة البث",
"Broadcast_hint": "يمكن فقط للمستخدمين المصرح لهم كتابة رسائل جديدة، ولكن سيتمكن المستخدمون الآخرون من الرد",
"Busy": "مشغول",
"By_proceeding_you_are_agreeing": "من خلال المتابعة، أنت توافق على",
"Cancel_editing": "إلغاء التعديل",
Expand Down Expand Up @@ -389,7 +388,6 @@
"Preferences": "التفضيلات",
"Preferences_saved": "تم حفظ التفضيلات",
"Privacy_Policy": "سياسة الخصوصية",
"Private_Channel": "قناة خاصة",
"Private": "خاص",
"Processing": "جار معالجة...",
"Profile_saved_successfully": "تم حفظ الملف الشخصي بنجاح!",
Expand All @@ -403,7 +401,6 @@
"Reactions": "التفاعلات",
"Read_External_Permission_Message": "يحتاج Rocket.chat للوصول إلى الصور والملفات الموجودة على الجهاز",
"Read_External_Permission": "صلاحية قراءة الوسائط",
"Read_Only_Channel": "قناة للقراءة فقط",
"Read_Only": "قراءة فقط",
"Read_Receipt": "قراءة المستلم",
"Receive_Group_Mentions": "تلقي إشارات المجموعة",
Expand Down
8 changes: 1 addition & 7 deletions app/i18n/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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!",
Expand All @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
Loading

0 comments on commit 9cbffff

Please sign in to comment.