Merge branch 'develop' into appium-v2

This commit is contained in:
GleidsonDaniel 2022-05-09 15:19:34 -03:00
commit 06e114416e
252 changed files with 2294 additions and 2043 deletions

View File

@ -144,7 +144,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode VERSIONCODE as Integer
versionName "4.27.0"
versionName "4.28.0"
vectorDrawables.useSupportLibrary = true
if (!isFoss) {
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -2,8 +2,16 @@ import { Action } from 'redux';
import { CREATE_DISCUSSION } from './actionsTypes';
export interface ICreateDiscussionRequestData {
prid: string;
pmid?: string;
t_name?: string;
reply?: string;
users: string[];
encrypted?: boolean;
}
interface ICreateDiscussionRequest extends Action {
data: any;
data: ICreateDiscussionRequestData;
}
interface ICreateDiscussionSuccess extends Action {

View File

@ -1,7 +1,7 @@
import { Action } from 'redux';
import { ICustomEmojis } from '../reducers/customEmojis';
import { SET_CUSTOM_EMOJIS } from './actionsTypes';
import { ICustomEmojis } from '../definitions';
export interface ISetCustomEmojis extends Action {
emojis: ICustomEmojis;

View File

@ -2,21 +2,15 @@ import React from 'react';
import { Text, View } from 'react-native';
import { themes } from '../../lib/constants';
import { CustomIcon } from '../../lib/Icons';
import { testProps } from '../../lib/methods/testProps';
import { CustomIcon } from '../CustomIcon';
import { useTheme } from '../../theme';
import { Button } from './Button';
import { TActionSheetOptionsItem } from './Provider';
import styles from './styles';
export interface IActionSheetItem {
item: {
title: string;
icon: string;
danger?: boolean;
testID?: string;
onPress: () => void;
right?: Function;
};
item: TActionSheetOptionsItem;
hide(): void;
}

View File

@ -1,13 +1,21 @@
import React, { ForwardedRef, forwardRef, useContext, useRef } from 'react';
import ActionSheet from './ActionSheet';
import { TIconsName } from '../CustomIcon';
export type TActionSheetOptionsItem = { title: string; icon: string; onPress: () => void; danger?: boolean };
export type TActionSheetOptionsItem = {
title: string;
icon: TIconsName;
danger?: boolean;
testID?: string;
onPress: () => void;
right?: () => React.ReactElement;
};
export type TActionSheetOptions = {
options: TActionSheetOptionsItem[];
headerHeight: number;
customHeader: React.ReactElement | null;
headerHeight?: number;
customHeader?: React.ReactElement | null;
hasCancel?: boolean;
};
interface IActionSheetProvider {

View File

@ -1,7 +1,7 @@
import React from 'react';
import { StyleSheet } from 'react-native';
import { CustomIcon } from '../lib/Icons';
import { CustomIcon } from './CustomIcon';
import { themes } from '../lib/constants';
import { useTheme } from '../theme';

View File

@ -0,0 +1,23 @@
import React from 'react';
import { createIconSetFromIcoMoon } from 'react-native-vector-icons';
import { TextProps } from 'react-native';
import { mappedIcons } from './mappedIcons';
const icoMoonConfig = require('./selection.json');
export const IconSet = createIconSetFromIcoMoon(icoMoonConfig, 'custom', 'custom.ttf');
export type TIconsName = keyof typeof mappedIcons;
interface ICustomIcon extends TextProps {
name: TIconsName;
size: number;
color: string;
}
const CustomIcon = ({ name, size, color, testID, ...props }: ICustomIcon) => (
// @ts-ignore TODO remove this after update @types/react-native to 0.65.0
<IconSet name={name} size={size} color={color} {...props} />
);
export { CustomIcon };

View File

@ -0,0 +1,202 @@
export const mappedIcons = {
attach: 59676,
link: 59752,
'status-away': 59741,
'status-busy': 59742,
'status-loading': 59743,
'status-offline': 59744,
'status-online': 59745,
'teams-private': 59750,
'channel-auto-join': 59746,
'channel-move-to-team': 59747,
'lock-filled': 59748,
locker: 59749,
teams: 59751,
shield: 59661,
ignore: 59740,
'checkbox-unchecked': 59648,
'checkbox-checked': 59649,
'github-monochromatic': 59650,
'gitlab-monochromatic': 59651,
'google-monochromatic': 59652,
'linkedin-monochromatic': 59653,
'meteor-monochromatic': 59654,
'twitter-monochromatic': 59655,
administration: 59657,
'adobe-reader-monochromatic': 59658,
'all-contacts-in-channels': 59659,
'all-contacts-in-queue': 59660,
'apple-monochromatic': 59662,
apps: 59663,
'arrow-back': 59664,
'arrow-collapse': 59665,
'arrow-decrease': 59666,
'arrow-down-box': 59667,
'arrow-down-circle': 59668,
'arrow-down': 59669,
'arrow-expand': 59670,
'arrow-increase': 59671,
'arrow-looping': 59672,
'arrow-return': 59673,
'arrow-up-box': 59674,
'arrow-up': 59675,
'audio-disabled': 59677,
'audio-unavailable': 59678,
audio: 59679,
auditing: 59680,
auth: 59681,
avatar: 59682,
backspace: 59683,
bold: 59684,
book: 59685,
business: 59686,
calendar: 59687,
'camera-disabled': 59688,
'camera-filled': 59689,
'camera-photo': 59690,
'camera-unavailable': 59691,
camera: 59692,
'canned-response': 59693,
card: 59694,
'channel-private': 59695,
'channel-public': 59696,
'chat-close': 59697,
'chat-forward': 59698,
check: 59699,
'chevron-down': 59700,
'chevron-left-big': 59701,
'chevron-left': 59702,
'chevron-right': 59703,
'chevron-up': 59704,
'circle-check': 59705,
clipboard: 59706,
clock: 59707,
close: 59708,
'cloud-connectivity': 59709,
code: 59710,
contacts: 59711,
copy: 59712,
create: 59713,
dashboard: 59714,
delete: 59715,
desktop: 59716,
dialpad: 59717,
'directory-disabled': 59718,
directory: 59719,
discussions: 59720,
document: 59721,
donner: 59722,
download: 59723,
edit: 59724,
'emoji-bad-mood': 59725,
'emoji-neutral-mood': 59726,
emoji: 59727,
encrypted: 59728,
'engagement-dashboard': 59729,
'enterprise-feature': 59730,
'facebook-monochromatic': 59731,
'file-document': 59732,
'file-sheet': 59733,
filter: 59734,
fingerprint: 59735,
flag: 59736,
folder: 59737,
game: 59738,
'giphy-monochromatic': 59739,
'google-drive-monochromatic': 59756,
'group-by-type': 59757,
hamburguer: 59758,
history: 59759,
home: 59760,
image: 59761,
info: 59762,
'input-clear': 59763,
instance: 59764,
italic: 59765,
'jump-backward': 59766,
'jump-forward': 59767,
'jump-to-message': 59768,
kebab: 59769,
keyboard: 59770,
language: 59771,
'live-streaming': 59773,
live: 59774,
'livechat-monochromatic': 59775,
'log-view': 59778,
login: 59779,
logout: 59780,
mail: 59781,
marketplace: 59782,
meatballs: 59783,
mention: 59784,
'message-disabled': 59785,
message: 59786,
'microphone-disabled': 59787,
microphone: 59788,
mobile: 59789,
moon: 59790,
'move-to-the-queue': 59791,
'musical-note': 59792,
'new-window': 59793,
'notification-disabled': 59794,
notification: 59795,
omnichannel: 59796,
order: 59797,
'ordering-ascending': 59798,
'ordering-descending': 59800,
'pause-filled': 59802,
pause: 59803,
'phone-disabled': 59804,
'phone-end': 59805,
phone: 59806,
'pin-map': 59807,
pin: 59808,
Pipe: 59809,
'play-filled': 59810,
play: 59811,
prune: 59817,
queue: 59818,
quote: 59819,
'reaction-add': 59820,
record: 59821,
refresh: 59822,
search: 59823,
'send-filled': 59824,
send: 59825,
settings: 59826,
share: 59827,
'shield-check': 59828,
'shield-alt': 59829,
signal: 59830,
'sort-az': 59831,
sort: 59832,
'star-filled': 59833,
star: 59834,
strike: 59846,
sun: 59847,
support: 59848,
team: 59849,
threads: 59850,
total: 59851,
transcript: 59852,
underline: 59853,
undo: 59854,
Unlimited: 59855,
'unread-on-top-disabled': 59856,
'unread-on-top': 59857,
upload: 59858,
'user-add': 59859,
'user-forward': 59860,
user: 59861,
'view-condensed': 59862,
'view-extended': 59863,
'view-medium': 59864,
'waiting-on-me': 59865,
warning: 59866,
'whatsapp-monochromatic': 59868,
'wordpress-monochromatic': 59656,
workspaces: 59870,
zip: 59871,
add: 59872,
sms: 59753
};

View File

@ -18,8 +18,8 @@ interface IDirectoryItemLabel {
interface IDirectoryItem {
title: string;
description: string;
avatar: string;
description?: string;
avatar?: string;
type: string;
onPress(): void;
testID: string;

View File

@ -8,7 +8,6 @@ const CustomEmoji = React.memo(
<FastImage
style={style}
source={{
// @ts-ignore
uri: `${baseUrl}/emoji-custom/${encodeURIComponent(emoji.content || emoji.name)}.${emoji.extension}`,
priority: FastImage.priority.high
}}

View File

@ -27,16 +27,17 @@ const renderEmoji = (emoji: IEmoji, size: number, baseUrl: string) => {
);
};
class EmojiCategory extends React.Component<Partial<IEmojiCategory>> {
renderItem(emoji: any) {
class EmojiCategory extends React.Component<IEmojiCategory> {
renderItem(emoji: IEmoji) {
const { baseUrl, onEmojiSelected } = this.props;
return (
<TouchableOpacity
activeOpacity={0.7}
// @ts-ignore
key={emoji && emoji.isCustom ? emoji.content : emoji}
onPress={() => onEmojiSelected!(emoji)}
onPress={() => onEmojiSelected(emoji)}
{...testProps(`reaction-picker-${emoji && emoji.isCustom ? emoji.content : emoji}`)}>
{renderEmoji(emoji, EMOJI_SIZE, baseUrl!)}
{renderEmoji(emoji, EMOJI_SIZE, baseUrl)}
</TouchableOpacity>
);
}
@ -52,7 +53,6 @@ class EmojiCategory extends React.Component<Partial<IEmojiCategory>> {
const marginHorizontal = (width - numColumns * EMOJI_SIZE) / 2;
return (
// @ts-ignore
<FlatList
contentContainerStyle={{ marginHorizontal }}
// rerender FlatList in case of width changes

View File

@ -1,5 +1,5 @@
import React from 'react';
import { Text, TouchableOpacity, View } from 'react-native';
import { StyleProp, Text, TextStyle, TouchableOpacity, View } from 'react-native';
import styles from './styles';
import { themes } from '../../lib/constants';
@ -7,15 +7,15 @@ import { testProps } from '../../lib/methods/testProps';
import { TSupportedThemes } from '../../theme';
interface ITabBarProps {
goToPage: Function;
activeTab: number;
tabs: [];
tabEmojiStyle: object;
goToPage?: (page: number) => void;
activeTab?: number;
tabs?: string[];
tabEmojiStyle: StyleProp<TextStyle>;
theme: TSupportedThemes;
}
export default class TabBar extends React.Component<Partial<ITabBarProps>> {
shouldComponentUpdate(nextProps: any) {
export default class TabBar extends React.Component<ITabBarProps> {
shouldComponentUpdate(nextProps: ITabBarProps) {
const { activeTab, theme } = this.props;
if (nextProps.activeTab !== activeTab) {
return true;
@ -31,16 +31,20 @@ export default class TabBar extends React.Component<Partial<ITabBarProps>> {
return (
<View style={styles.tabsContainer}>
{tabs!.map((tab, i) => (
{tabs?.map((tab, i) => (
<TouchableOpacity
activeOpacity={0.7}
key={tab}
onPress={() => goToPage!(i)}
onPress={() => {
if (goToPage) {
goToPage(i);
}
}}
style={styles.tab}
{...testProps(`reaction-picker-${tab}`)}>
<Text style={[styles.tabEmoji, tabEmojiStyle]}>{tab}</Text>
{activeTab === i ? (
<View style={[styles.activeTabLine, { backgroundColor: themes[theme!].tintColor }]} />
<View style={[styles.activeTabLine, { backgroundColor: themes[theme].tintColor }]} />
) : (
<View style={styles.tabLine} />
)}

View File

@ -1,4 +1,4 @@
export const emojisByCategory: any = {
export const emojisByCategory = {
people: [
'grinning',
'grimacing',

View File

@ -1,38 +1,34 @@
import React, { Component } from 'react';
import { View } from 'react-native';
import { StyleProp, TextStyle, View } from 'react-native';
import ScrollableTabView from 'react-native-scrollable-tab-view';
import { dequal } from 'dequal';
import { connect } from 'react-redux';
import orderBy from 'lodash/orderBy';
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
import { ImageStyle } from '@rocket.chat/react-native-fast-image';
import TabBar from './TabBar';
import EmojiCategory from './EmojiCategory';
import styles from './styles';
import categories from './categories';
import database from '../../lib/database';
import { emojisByCategory } from '../../emojis';
import { emojisByCategory } from './emojis';
import protectedFunction from '../../lib/methods/helpers/protectedFunction';
import shortnameToUnicode from '../../utils/shortnameToUnicode';
import log from '../../utils/log';
import { themes } from '../../lib/constants';
import { TSupportedThemes, withTheme } from '../../theme';
import { IEmoji } from '../../definitions/IEmoji';
const scrollProps = {
keyboardShouldPersistTaps: 'always',
keyboardDismissMode: 'none'
};
import { IEmoji, TGetCustomEmoji, IApplicationState, ICustomEmojis, TFrequentlyUsedEmojiModel } from '../../definitions';
interface IEmojiPickerProps {
isMessageContainsOnlyEmoji: boolean;
getCustomEmoji?: Function;
isMessageContainsOnlyEmoji?: boolean;
getCustomEmoji?: TGetCustomEmoji;
baseUrl: string;
customEmojis?: any;
style: object;
customEmojis: ICustomEmojis;
style?: StyleProp<ImageStyle>;
theme: TSupportedThemes;
onEmojiSelected?: ((emoji: any) => void) | ((keyboardId: any, params?: any) => void);
tabEmojiStyle?: object;
onEmojiSelected: (emoji: string, shortname?: string) => void;
tabEmojiStyle?: StyleProp<TextStyle>;
}
interface IEmojiPickerState {
@ -65,7 +61,7 @@ class EmojiPicker extends Component<IEmojiPickerProps, IEmojiPickerState> {
this.setState({ show: true });
}
shouldComponentUpdate(nextProps: any, nextState: any) {
shouldComponentUpdate(nextProps: IEmojiPickerProps, nextState: IEmojiPickerState) {
const { frequentlyUsed, show, width } = this.state;
const { theme } = this.props;
if (nextProps.theme !== theme) {
@ -92,12 +88,12 @@ class EmojiPicker extends Component<IEmojiPickerProps, IEmojiPickerState> {
extension: emoji.extension,
isCustom: true
});
onEmojiSelected!(`:${emoji.content}:`);
onEmojiSelected(`:${emoji.content}:`);
} else {
const content = emoji;
this._addFrequentlyUsed({ content, isCustom: false });
const shortname = `:${emoji}:`;
onEmojiSelected!(shortnameToUnicode(shortname), shortname);
onEmojiSelected(shortnameToUnicode(shortname), shortname);
}
} catch (e) {
log(e);
@ -107,9 +103,8 @@ class EmojiPicker extends Component<IEmojiPickerProps, IEmojiPickerState> {
_addFrequentlyUsed = protectedFunction(async (emoji: IEmoji) => {
const db = database.active;
const freqEmojiCollection = db.get('frequently_used_emojis');
let freqEmojiRecord: any;
let freqEmojiRecord: TFrequentlyUsedEmojiModel;
try {
// @ts-ignore
freqEmojiRecord = await freqEmojiCollection.find(emoji.content);
} catch (error) {
// Do nothing
@ -117,11 +112,13 @@ class EmojiPicker extends Component<IEmojiPickerProps, IEmojiPickerState> {
await db.write(async () => {
if (freqEmojiRecord) {
await freqEmojiRecord.update((f: any) => {
f.count += 1;
await freqEmojiRecord.update(f => {
if (f.count) {
f.count += 1;
}
});
} else {
await freqEmojiCollection.create((f: any) => {
await freqEmojiCollection.create(f => {
f._raw = sanitizedRaw({ id: emoji.content }, freqEmojiCollection.schema);
Object.assign(f, emoji);
f.count = 1;
@ -149,7 +146,7 @@ class EmojiPicker extends Component<IEmojiPickerProps, IEmojiPickerState> {
}
}: any) => this.setState({ width });
renderCategory(category: any, i: number, label: string) {
renderCategory(category: keyof typeof emojisByCategory, i: number, label: string) {
const { frequentlyUsed, customEmojis, width } = this.state;
const { baseUrl } = this.props;
@ -166,7 +163,7 @@ class EmojiPicker extends Component<IEmojiPickerProps, IEmojiPickerState> {
emojis={emojis}
onEmojiSelected={(emoji: IEmoji) => this.onEmojiSelected(emoji)}
style={styles.categoryContainer}
width={width!}
width={width}
baseUrl={baseUrl}
tabLabel={label}
/>
@ -184,10 +181,12 @@ class EmojiPicker extends Component<IEmojiPickerProps, IEmojiPickerState> {
<View onLayout={this.onLayout} style={{ flex: 1 }}>
<ScrollableTabView
renderTabBar={() => <TabBar tabEmojiStyle={tabEmojiStyle} theme={theme} />}
/* @ts-ignore*/
contentProps={scrollProps}
contentProps={{
keyboardShouldPersistTaps: 'always',
keyboardDismissMode: 'none'
}}
style={{ backgroundColor: themes[theme].focusedBackground }}>
{categories.tabs.map((tab, i) =>
{categories.tabs.map((tab: any, i) =>
i === 0 && frequentlyUsed.length === 0
? null // when no frequentlyUsed don't show the tab
: this.renderCategory(tab.category, i, tab.tabLabel)
@ -198,9 +197,8 @@ class EmojiPicker extends Component<IEmojiPickerProps, IEmojiPickerState> {
}
}
const mapStateToProps = (state: any) => ({
const mapStateToProps = (state: IApplicationState) => ({
customEmojis: state.customEmojis
});
// TODO - remove this as any, at the new PR to fix the HOC erros
export default connect(mapStateToProps)(withTheme(EmojiPicker)) as any;
export default connect(mapStateToProps)(withTheme(EmojiPicker));

View File

@ -2,7 +2,7 @@ import React from 'react';
import { Platform, StyleSheet, Text } from 'react-native';
import Touchable from 'react-native-platform-touchable';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon, TIconsName } from '../CustomIcon';
import { useTheme } from '../../theme';
import { themes } from '../../lib/constants';
import sharedStyles from '../../views/Styles';
@ -10,7 +10,7 @@ import { testProps } from '../../lib/methods/testProps';
interface IHeaderButtonItem {
title?: string;
iconName?: string;
iconName?: TIconsName;
onPress?: <T>(arg: T) => void;
testID?: string;
badge?(): void;

View File

@ -6,7 +6,7 @@ import { Notifier } from 'react-native-notifier';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import Avatar from '../Avatar';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import sharedStyles from '../../views/Styles';
import { themes } from '../../lib/constants';
import { useTheme } from '../../theme';
@ -136,7 +136,7 @@ const NotifierComponent = React.memo(({ notification, isMasterDetail }: INotifie
</>
</Touchable>
<Touchable onPress={hideNotification} hitSlop={BUTTON_HIT_SLOP} background={Touchable.SelectableBackgroundBorderless()}>
<CustomIcon name='close' style={[styles.close, { color: themes[theme].titleText }]} size={20} />
<CustomIcon name='close' size={20} color={themes[theme].titleText} style={styles.close} />
</Touchable>
</View>
);

View File

@ -2,13 +2,13 @@ import React from 'react';
import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native';
import { themes } from '../../lib/constants';
import { CustomIcon } from '../../lib/Icons';
import { testProps } from '../../lib/methods/testProps';
import { CustomIcon, TIconsName } from '../CustomIcon';
import { useTheme } from '../../theme';
import { ICON_SIZE } from './constants';
interface IListIcon {
name: string;
name: TIconsName;
color?: string | null;
style?: StyleProp<ViewStyle>;
testID?: string;

View File

@ -9,8 +9,8 @@ import I18n from '../../i18n';
import { Icon } from '.';
import { BASE_HEIGHT, ICON_SIZE, PADDING_HORIZONTAL } from './constants';
import { useDimensions } from '../../dimensions';
import { CustomIcon } from '../../lib/Icons';
import { testProps } from '../../lib/methods/testProps';
import { CustomIcon } from '../CustomIcon';
const styles = StyleSheet.create({
container: {
@ -97,7 +97,7 @@ const Content = React.memo(
{translateTitle && title ? I18n.t(title) : title}
</Text>
{alert ? (
<CustomIcon style={[styles.alertIcon, { color: themes[theme].dangerColor }]} size={ICON_SIZE} name='info' />
<CustomIcon name='info' size={ICON_SIZE} color={themes[theme].dangerColor} style={styles.alertIcon} />
) : null}
</View>
{subtitle ? (

View File

@ -1,9 +1,18 @@
import React from 'react';
import { Animated, Modal, StyleSheet, View } from 'react-native';
import React, { useEffect } from 'react';
import { Animated, Modal, PixelRatio, StyleSheet, View } from 'react-native';
import {
cancelAnimation,
Extrapolate,
interpolate,
useAnimatedStyle,
useSharedValue,
withRepeat,
withSequence,
withTiming
} from 'react-native-reanimated';
import { TSupportedThemes, withTheme } from '../theme';
import { themes } from '../lib/constants';
import { testProps } from '../lib/methods/testProps';
import { useTheme } from '../theme';
const styles = StyleSheet.create({
container: {
@ -12,130 +21,54 @@ const styles = StyleSheet.create({
justifyContent: 'center'
},
image: {
width: 100,
height: 100,
width: PixelRatio.get() * 40,
height: PixelRatio.get() * 40,
resizeMode: 'contain'
}
});
interface ILoadingProps {
visible: boolean;
theme?: TSupportedThemes;
}
interface ILoadingState {
scale: Animated.Value;
opacity: Animated.Value;
}
class Loading extends React.PureComponent<ILoadingProps, ILoadingState> {
state = {
scale: new Animated.Value(1),
opacity: new Animated.Value(0)
};
private opacityAnimation?: Animated.CompositeAnimation;
private scaleAnimation?: Animated.CompositeAnimation;
componentDidMount() {
const { opacity, scale } = this.state;
const { visible } = this.props;
this.opacityAnimation = Animated.timing(opacity, {
toValue: 1,
duration: 200,
useNativeDriver: true
});
this.scaleAnimation = Animated.loop(
Animated.sequence([
Animated.timing(scale, {
toValue: 0,
duration: 1000,
useNativeDriver: true
}),
Animated.timing(scale, {
toValue: 1,
duration: 1000,
useNativeDriver: true
})
])
);
const Loading = ({ visible }: ILoadingProps): React.ReactElement => {
const opacity = useSharedValue(0);
const scale = useSharedValue(1);
const { colors } = useTheme();
useEffect(() => {
if (visible) {
this.startAnimations();
opacity.value = withTiming(1, {
duration: 200
});
scale.value = withRepeat(withSequence(withTiming(0, { duration: 1000 }), withTiming(1, { duration: 1000 })), -1);
}
}
return () => {
cancelAnimation(scale);
};
}, [opacity, scale, visible]);
componentDidUpdate(prevProps: ILoadingProps) {
const { visible } = this.props;
if (visible && visible !== prevProps.visible) {
this.startAnimations();
}
}
const animatedOpacity = useAnimatedStyle(() => ({
opacity: interpolate(opacity.value, [0, 1], [0, colors.backdropOpacity], Extrapolate.CLAMP)
}));
const animatedScale = useAnimatedStyle(() => ({ transform: [{ scale: interpolate(scale.value, [0, 0.5, 1], [1, 1.1, 1]) }] }));
componentWillUnmount() {
if (this.opacityAnimation && this.opacityAnimation.stop) {
this.opacityAnimation.stop();
}
if (this.scaleAnimation && this.scaleAnimation.stop) {
this.scaleAnimation.stop();
}
}
return (
<Modal visible={visible} transparent onRequestClose={() => {}}>
<View style={styles.container} {...testProps('loading')}>
<Animated.View
style={[
{
...StyleSheet.absoluteFillObject,
backgroundColor: colors.backdropColor
},
animatedOpacity
]}
/>
<Animated.Image source={require('../static/images/logo.png')} style={[styles.image, animatedScale]} />
</View>
</Modal>
);
};
startAnimations() {
if (this.opacityAnimation && this.opacityAnimation.start) {
this.opacityAnimation.start();
}
if (this.scaleAnimation && this.scaleAnimation.start) {
this.scaleAnimation.start();
}
}
render() {
const { opacity, scale } = this.state;
const { visible, theme } = this.props;
const scaleAnimation = scale.interpolate({
inputRange: [0, 0.5, 1],
outputRange: [1, 1.1, 1]
});
const opacityAnimation = opacity.interpolate({
inputRange: [0, 1],
outputRange: [0, themes[theme!].backdropOpacity],
extrapolate: 'clamp'
});
return (
<Modal visible={visible} transparent onRequestClose={() => {}}>
<View style={styles.container} {...testProps('loading')}>
<Animated.View
style={[
{
...StyleSheet.absoluteFillObject,
backgroundColor: themes[theme!].backdropColor,
opacity: opacityAnimation
}
]}
/>
<Animated.Image
source={require('../static/images/logo.png')}
style={[
styles.image,
{
transform: [
{
scale: scaleAnimation
}
]
}
]}
/>
</View>
</Modal>
);
}
}
export default withTheme(Loading);
export default Loading;

View File

@ -14,11 +14,11 @@ import Touch from '../utils/touch';
import I18n from '../i18n';
import random from '../utils/random';
import { events, logEvent } from '../utils/log';
import RocketChat from '../lib/rocketchat';
import { CustomIcon } from '../lib/Icons';
import { CustomIcon, TIconsName } from './CustomIcon';
import { IServices } from '../selectors/login';
import { OutsideParamList } from '../stacks/types';
import { IApplicationState } from '../definitions';
import { Services } from '../lib/services';
const BUTTON_HEIGHT = 48;
const SERVICE_HEIGHT = 58;
@ -248,7 +248,7 @@ class LoginServices extends React.PureComponent<ILoginServicesProps, ILoginServi
AppleAuthentication.AppleAuthenticationScope.EMAIL
]
});
await RocketChat.loginOAuthOrSso({ fullName, email, identityToken });
await Services.loginOAuthOrSso({ fullName, email, identityToken });
} catch {
logEvent(events.ENTER_WITH_APPLE_F);
}
@ -345,7 +345,7 @@ class LoginServices extends React.PureComponent<ILoginServicesProps, ILoginServi
const { CAS_enabled, theme } = this.props;
let { name } = service;
name = name === 'meteor-developer' ? 'meteor' : name;
const icon = `${name}-monochromatic`;
const icon = `${name}-monochromatic` as TIconsName;
const isSaml = service.service === 'saml';
let onPress = () => {};

View File

@ -3,17 +3,15 @@ import { FlatList, StyleSheet, Text, View } from 'react-native';
import { TSupportedThemes, useTheme } from '../../theme';
import { themes } from '../../lib/constants';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import shortnameToUnicode from '../../utils/shortnameToUnicode';
import CustomEmoji from '../EmojiPicker/CustomEmoji';
import database from '../../lib/database';
import { Button } from '../ActionSheet';
import { useDimensions } from '../../dimensions';
import sharedStyles from '../../views/Styles';
import { TFrequentlyUsedEmojiModel } from '../../definitions/IFrequentlyUsedEmoji';
import { TAnyMessageModel } from '../../definitions';
import { IEmoji } from '../../definitions/IEmoji';
import { testProps } from '../../lib/methods/testProps';
import { TAnyMessageModel, TFrequentlyUsedEmojiModel } from '../../definitions';
type TItem = TFrequentlyUsedEmojiModel | string;
@ -84,7 +82,7 @@ const HeaderItem = ({ item, onReaction, server, theme }: THeaderItem) => {
style={[styles.headerItem, { backgroundColor: themes[theme].auxiliaryBackground }]}
theme={theme}>
{emojiModel?.isCustom ? (
<CustomEmoji style={styles.customEmoji} emoji={emojiModel as IEmoji} baseUrl={server} />
<CustomEmoji style={styles.customEmoji} emoji={emojiModel} baseUrl={server} />
) : (
<Text style={styles.headerIcon}>{shortnameToUnicode(`:${emoji}:`)}</Text>
)}

View File

@ -4,7 +4,6 @@ import Clipboard from '@react-native-clipboard/clipboard';
import { connect } from 'react-redux';
import moment from 'moment';
import RocketChat from '../../lib/rocketchat';
import database from '../../lib/database';
import I18n from '../../i18n';
import log, { logEvent } from '../../utils/log';
@ -17,8 +16,10 @@ import { TActionSheetOptionsItem, useActionSheet } from '../ActionSheet';
import Header, { HEADER_HEIGHT, IHeader } from './Header';
import events from '../../utils/log/events';
import { IApplicationState, ILoggedUser, TAnyMessageModel, TSubscriptionModel } from '../../definitions';
import { getPermalinkMessage, hasPermission } from '../../lib/methods';
import { Services } from '../../lib/services';
export interface IMessageActions {
export interface IMessageActionsProps {
room: TSubscriptionModel;
tmid?: string;
user: Pick<ILoggedUser, 'id'>;
@ -42,8 +43,12 @@ export interface IMessageActions {
pinMessagePermission?: string[];
}
export interface IMessageActions {
showMessageActions: (message: TAnyMessageModel) => Promise<void>;
}
const MessageActions = React.memo(
forwardRef(
forwardRef<IMessageActions, IMessageActionsProps>(
(
{
room,
@ -67,7 +72,7 @@ const MessageActions = React.memo(
deleteMessagePermission,
forceDeleteMessagePermission,
pinMessagePermission
}: IMessageActions,
},
ref
) => {
let permissions = {
@ -81,7 +86,7 @@ const MessageActions = React.memo(
const getPermissions = async () => {
try {
const permission = [editMessagePermission, deleteMessagePermission, forceDeleteMessagePermission, pinMessagePermission];
const result = await RocketChat.hasPermission(permission, room.rid);
const result = await hasPermission(permission, room.rid);
permissions = {
hasEditPermission: result[0],
hasDeletePermission: result[1],
@ -150,7 +155,7 @@ const MessageActions = React.memo(
return true;
};
const getPermalink = (message: TAnyMessageModel) => RocketChat.getPermalinkMessage(message);
const getPermalink = (message: TAnyMessageModel) => getPermalinkMessage(message);
const handleReply = (message: TAnyMessageModel) => {
logEvent(events.ROOM_MSG_ACTION_REPLY);
@ -178,7 +183,7 @@ const MessageActions = React.memo(
const { rid } = room;
try {
const db = database.active;
const result = await RocketChat.markAsUnread({ messageId });
const result = await Services.markAsUnread({ messageId });
if (result.success) {
const subCollection = db.get('subscriptions');
const subRecord = await subCollection.find(rid);
@ -234,7 +239,7 @@ const MessageActions = React.memo(
const handleStar = async (message: TAnyMessageModel) => {
logEvent(message.starred ? events.ROOM_MSG_ACTION_UNSTAR : events.ROOM_MSG_ACTION_STAR);
try {
await RocketChat.toggleStarMessage(message.id, message.starred as boolean); // TODO: reevaluate `message.starred` type on IMessage
await Services.toggleStarMessage(message.id, message.starred as boolean); // TODO: reevaluate `message.starred` type on IMessage
EventEmitter.emit(LISTENER, { message: message.starred ? I18n.t('Message_unstarred') : I18n.t('Message_starred') });
} catch (e) {
logEvent(events.ROOM_MSG_ACTION_STAR_F);
@ -245,7 +250,7 @@ const MessageActions = React.memo(
const handlePin = async (message: TAnyMessageModel) => {
logEvent(events.ROOM_MSG_ACTION_PIN);
try {
await RocketChat.togglePinMessage(message.id, message.pinned as boolean); // TODO: reevaluate `message.pinned` type on IMessage
await Services.togglePinMessage(message.id, message.pinned as boolean); // TODO: reevaluate `message.pinned` type on IMessage
} catch (e) {
logEvent(events.ROOM_MSG_ACTION_PIN_F);
log(e);
@ -292,7 +297,7 @@ const MessageActions = React.memo(
u: message.u,
msg: message.msg
};
await RocketChat.translateMessage(m, room.autoTranslateLanguage);
await Services.translateMessage(m, room.autoTranslateLanguage);
}
} catch (e) {
log(e);
@ -302,7 +307,7 @@ const MessageActions = React.memo(
const handleReport = async (message: TAnyMessageModel) => {
logEvent(events.ROOM_MSG_ACTION_REPORT);
try {
await RocketChat.reportMessage(message.id);
await Services.reportMessage(message.id);
Alert.alert(I18n.t('Message_Reported'));
} catch (e) {
logEvent(events.ROOM_MSG_ACTION_REPORT_F);
@ -317,7 +322,7 @@ const MessageActions = React.memo(
onPress: async () => {
try {
logEvent(events.ROOM_MSG_ACTION_DELETE);
await RocketChat.deleteMessage(message.id, message.subscription ? message.subscription.id : '');
await Services.deleteMessage(message.id, message.subscription ? message.subscription.id : '');
} catch (e) {
logEvent(events.ROOM_MSG_ACTION_DELETE_F);
log(e);

View File

@ -3,8 +3,8 @@ import React, { useContext, useState } from 'react';
import { TouchableOpacity } from 'react-native';
import { themes } from '../../../lib/constants';
import { CustomIcon } from '../../../lib/Icons';
import { testProps } from '../../../lib/methods/testProps';
import { CustomIcon } from '../../CustomIcon';
import { useTheme } from '../../../theme';
import ActivityIndicator from '../../ActivityIndicator';
import MessageboxContext from '../Context';

View File

@ -7,7 +7,6 @@ import EmojiPicker from '../EmojiPicker';
import styles from './styles';
import { themes } from '../../lib/constants';
import { TSupportedThemes, withTheme } from '../../theme';
import { IEmoji } from '../../definitions/IEmoji';
import { testProps } from '../../lib/methods/testProps';
interface IMessageBoxEmojiKeyboard {
@ -23,7 +22,7 @@ export default class EmojiKeyboard extends React.PureComponent<IMessageBoxEmojiK
this.baseUrl = state.share.server.server || state.server.server;
}
onEmojiSelected = (emoji: IEmoji) => {
onEmojiSelected = (emoji: string) => {
KeyboardRegistry.onItemSelected('EmojiKeyboard', { emoji });
};
@ -33,7 +32,7 @@ export default class EmojiKeyboard extends React.PureComponent<IMessageBoxEmojiK
<View
style={[styles.emojiKeyboardContainer, { borderTopColor: themes[theme].borderColor }]}
{...testProps('messagebox-keyboard-emoji')}>
<EmojiPicker onEmojiSelected={this.onEmojiSelected} baseUrl={this.baseUrl} />
<EmojiPicker onEmojiSelected={this.onEmojiSelected} baseUrl={this.baseUrl} theme={theme} />
</View>
);
}

View File

@ -3,7 +3,7 @@ import { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native';
import { themes } from '../../../lib/constants';
import I18n from '../../../i18n';
import { CustomIcon } from '../../../lib/Icons';
import { CustomIcon } from '../../CustomIcon';
import { useTheme } from '../../../theme';
import sharedStyles from '../../../views/Styles';
import MessageboxContext from '../Context';

View File

@ -8,7 +8,7 @@ import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake';
import styles from './styles';
import I18n from '../../i18n';
import { themes } from '../../lib/constants';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import { events, logEvent } from '../../utils/log';
import { testProps } from '../../lib/methods/testProps';
import { TSupportedThemes } from '../../theme';

View File

@ -4,7 +4,7 @@ import moment from 'moment';
import { connect } from 'react-redux';
import { MarkdownPreview } from '../markdown';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import sharedStyles from '../../views/Styles';
import { themes } from '../../lib/constants';
import { IMessage } from '../../definitions/IMessage';

View File

@ -3,7 +3,7 @@ import React from 'react';
import { View } from 'react-native';
import styles from '../styles';
import { CustomIcon } from '../../../lib/Icons';
import { CustomIcon, TIconsName } from '../../CustomIcon';
import { useTheme } from '../../../theme';
import { themes } from '../../../lib/constants';
import { testProps } from '../../../lib/methods/testProps';
@ -13,11 +13,11 @@ interface IBaseButton {
onPress(): void;
testID: string;
accessibilityLabel: string;
icon: string;
color: string;
icon: TIconsName;
color?: string;
}
const BaseButton = ({ accessibilityLabel, icon, color, ...props }: Partial<IBaseButton>) => {
const BaseButton = ({ accessibilityLabel, icon, color, ...props }: IBaseButton) => {
const { theme } = useTheme();
return (
<BorderlessButton {...props} style={styles.actionButton} {...testProps(props.testID)}>

View File

@ -11,10 +11,9 @@ import { TouchableWithoutFeedback } from 'react-native-gesture-handler';
import { generateTriggerId } from '../../lib/methods/actions';
import TextInput, { IThemedTextInput } from '../../presentation/TextInput';
import { userTyping as userTypingAction } from '../../actions/room';
import RocketChat from '../../lib/rocketchat';
import styles from './styles';
import database from '../../lib/database';
import { emojis } from '../../emojis';
import { emojis } from '../EmojiPicker/emojis';
import log, { events, logEvent } from '../../utils/log';
import RecordAudio from './RecordAudio';
import I18n from '../../i18n';
@ -47,12 +46,14 @@ import { getUserSelector } from '../../selectors/login';
import Navigation from '../../lib/navigation/appNavigation';
import { withActionSheet } from '../ActionSheet';
import { sanitizeLikeString } from '../../lib/database/utils';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import { IMessage } from '../../definitions/IMessage';
import { forceJpgExtension } from './forceJpgExtension';
import { IBaseScreen, IPreviewItem, IUser, TSubscriptionModel, TThreadModel } from '../../definitions';
import { IBaseScreen, IPreviewItem, IUser, TGetCustomEmoji, TSubscriptionModel, TThreadModel } from '../../definitions';
import { MasterDetailInsideStackParamList } from '../../stacks/MasterDetailStack/types';
import { testProps } from '../../lib/methods/testProps';
import { getPermalinkMessage, hasPermission, search, sendFileMessage } from '../../lib/methods';
import { Services } from '../../lib/services';
import { TSupportedThemes } from '../../theme';
if (isAndroid) {
@ -92,7 +93,7 @@ export interface IMessageBoxProps extends IBaseScreen<MasterDetailInsideStackPar
FileUpload_MediaTypeWhiteList: string;
FileUpload_MaxFileSize: number;
Message_AudioRecorderEnabled: boolean;
getCustomEmoji: Function;
getCustomEmoji: TGetCustomEmoji;
editCancel: Function;
editRequest: Function;
onSubmit: Function;
@ -128,7 +129,7 @@ interface IMessageBoxState {
}
class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
private text: string;
public text: string;
private selection: { start: number; end: number };
@ -409,7 +410,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
return;
}
const permissionToUpload = await RocketChat.hasPermission([uploadFilePermission], rid);
const permissionToUpload = await hasPermission([uploadFilePermission], rid);
this.setState({ permissionToUpload: permissionToUpload[0] });
};
@ -530,14 +531,14 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
try {
const { appId } = command;
const triggerId = generateTriggerId(appId);
RocketChat.executeCommandPreview(name, params, rid, item, triggerId, tmid || messageTmid);
Services.executeCommandPreview(name, params, rid, item, triggerId, tmid || messageTmid);
replyCancel();
} catch (e) {
log(e);
}
};
onEmojiSelected = (keyboardId: any, params: any) => {
onEmojiSelected = (keyboardId: string, params: { emoji: string }) => {
const { text } = this;
const { emoji } = params;
let newText = '';
@ -553,7 +554,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
getPermalink = async (message: any) => {
try {
return await RocketChat.getPermalinkMessage(message);
return await getPermalinkMessage(message);
} catch (error) {
return null;
}
@ -571,13 +572,13 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
};
getUsers = debounce(async (keyword: any) => {
let res = await RocketChat.search({ text: keyword, filterRooms: false, filterUsers: true });
let res = await search({ text: keyword, filterRooms: false, filterUsers: true });
res = [...this.getFixedMentions(keyword), ...res];
this.setState({ mentions: res, mentionLoading: false });
}, 300);
getRooms = debounce(async (keyword = '') => {
const res = await RocketChat.search({ text: keyword, filterRooms: true, filterUsers: false });
const res = await search({ text: keyword, filterRooms: true, filterUsers: false });
this.setState({ mentions: res, mentionLoading: false });
}, 300);
@ -605,7 +606,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
}, 300);
getCannedResponses = debounce(async (text?: string) => {
const res = await RocketChat.getListCannedResponse({ text });
const res = await Services.getListCannedResponse({ text });
this.setState({ mentions: res.success ? res.cannedResponses : [], mentionLoading: false });
}, 500);
@ -642,7 +643,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
setCommandPreview = async (command: any, name: string, params: string) => {
const { rid } = this.props;
try {
const response = await RocketChat.getCommandPreview(name, rid, params);
const response = await Services.getCommandPreview(name, rid, params);
if (response.success) {
return this.setState({ commandPreview: response.preview?.items || [], showCommandPreview: true, command });
}
@ -837,7 +838,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
if (fileInfo) {
try {
if (this.canUploadFile(fileInfo)) {
await RocketChat.sendFileMessage(rid, fileInfo, tmid, server, user);
await sendFileMessage(rid, fileInfo, tmid, server, user);
}
} catch (e) {
log(e);
@ -889,7 +890,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
const messageWithoutCommand = message.replace(/([^\s]+)/, '').trim();
const [{ appId }] = slashCommand;
const triggerId = generateTriggerId(appId);
await RocketChat.runSlashCommand(command, roomId, messageWithoutCommand, triggerId, tmid || messageTmid);
await Services.runSlashCommand(command, roomId, messageWithoutCommand, triggerId, tmid || messageTmid);
replyCancel();
} catch (e) {
logEvent(events.COMMAND_RUN_F);
@ -1182,4 +1183,6 @@ const dispatchToProps = {
typing: (rid: any, status: any) => userTypingAction(rid, status)
};
export default connect(mapStateToProps, dispatchToProps, null, { forwardRef: true })(withActionSheet(MessageBox)) as any;
export type MessageBoxType = MessageBox;
export default connect(mapStateToProps, dispatchToProps, null, { forwardRef: true })(withActionSheet(MessageBox));

View File

@ -1,20 +1,23 @@
import { forwardRef, useImperativeHandle } from 'react';
import Model from '@nozbe/watermelondb/Model';
import RocketChat from '../lib/rocketchat';
import database from '../lib/database';
import protectedFunction from '../lib/methods/helpers/protectedFunction';
import { useActionSheet } from './ActionSheet';
import I18n from '../i18n';
import log from '../utils/log';
import { TMessageModel } from '../definitions';
import { resendMessage } from '../lib/methods';
const MessageErrorActions = forwardRef(({ tmid }: { tmid: string }, ref) => {
// TODO - remove this any after merge ActionSheet evaluate
const { showActionSheet }: any = useActionSheet();
export interface IMessageErrorActions {
showMessageErrorActions: (message: TMessageModel) => void;
}
const MessageErrorActions = forwardRef<IMessageErrorActions, { tmid?: string }>(({ tmid }, ref) => {
const { showActionSheet } = useActionSheet();
const handleResend = protectedFunction(async (message: TMessageModel) => {
await RocketChat.resendMessage(message, tmid);
await resendMessage(message, tmid);
});
const handleDelete = async (message: TMessageModel) => {

View File

@ -4,12 +4,12 @@ import { Text } from 'react-native';
import styles from './styles';
import { themes } from '../../../lib/constants';
import Touch from '../../../utils/touch';
import { CustomIcon } from '../../../lib/Icons';
import { CustomIcon, TIconsName } from '../../CustomIcon';
import { useTheme } from '../../../theme';
interface IPasscodeButton {
text?: string;
icon?: string;
icon?: TIconsName;
disabled?: boolean;
onPress?: Function;
}

View File

@ -4,7 +4,7 @@ import { Row } from 'react-native-easy-grid';
import styles from './styles';
import { themes } from '../../../lib/constants';
import { CustomIcon } from '../../../lib/Icons';
import { CustomIcon } from '../../CustomIcon';
import { useTheme } from '../../../theme';
const LockIcon = React.memo(() => {

View File

@ -5,7 +5,7 @@ import Touchable from 'react-native-platform-touchable';
import Emoji from './message/Emoji';
import I18n from '../i18n';
import { CustomIcon } from '../lib/Icons';
import { CustomIcon } from './CustomIcon';
import sharedStyles from '../views/Styles';
import { themes } from '../lib/constants';
import { TSupportedThemes, useTheme, withTheme } from '../theme';
@ -125,7 +125,7 @@ const ModalContent = React.memo(({ message, onClose, ...props }: IModalContent)
<SafeAreaView style={styles.safeArea}>
<Touchable onPress={onClose}>
<View style={styles.titleContainer}>
<CustomIcon style={[styles.closeButton, { color: themes[props.theme].buttonText }]} name='close' size={20} />
<CustomIcon name='close' size={20} color={themes[props.theme].buttonText} style={styles.closeButton} />
<Text style={[styles.title, { color: themes[props.theme].buttonText }]}>{I18n.t('Reactions')}</Text>
</View>
</Touchable>

File diff suppressed because one or more lines are too long

View File

@ -3,7 +3,7 @@ import { Animated, View } from 'react-native';
import { RectButton } from 'react-native-gesture-handler';
import { isRTL } from '../../i18n';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import { DisplayMode, themes } from '../../lib/constants';
import styles, { ACTION_WIDTH, LONG_SWIPE, ROW_HEIGHT_CONDENSED } from './styles';
import { ILeftActionsProps, IRightActionsProps } from './interfaces';

View File

@ -3,7 +3,7 @@ import React from 'react';
import RoomTypeIcon from '../RoomTypeIcon';
import { ITypeIconProps } from './interfaces';
const TypeIcon = React.memo(({ type, prid, status, isGroupChat, teamMain, size, style }: ITypeIconProps) => (
const TypeIcon = React.memo(({ type, prid, status, isGroupChat, teamMain, size, style, sourceType }: ITypeIconProps) => (
<RoomTypeIcon
type={prid ? 'discussion' : type}
isGroupChat={isGroupChat}
@ -11,6 +11,7 @@ const TypeIcon = React.memo(({ type, prid, status, isGroupChat, teamMain, size,
teamMain={teamMain}
size={size}
style={style}
sourceType={sourceType}
/>
));

View File

@ -5,9 +5,13 @@ import { useSelector } from 'react-redux';
import { OmnichannelSourceType, IApplicationState, IOmnichannelSource } from '../../definitions';
import { STATUS_COLORS } from '../../lib/constants';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon, TIconsName } from '../CustomIcon';
const iconMap = {
interface IIconMap {
[key: string]: TIconsName;
}
const iconMap: IIconMap = {
widget: 'livechat-monochromatic',
email: 'mail',
sms: 'sms',

View File

@ -2,7 +2,7 @@ import React from 'react';
import { StyleSheet, ViewStyle } from 'react-native';
import { OmnichannelRoomIcon } from './OmnichannelRoomIcon';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon, TIconsName } from '../CustomIcon';
import { STATUS_COLORS, themes } from '../../lib/constants';
import Status from '../Status/Status';
import { useTheme } from '../../theme';
@ -46,7 +46,7 @@ const RoomTypeIcon = React.memo(({ type, isGroupChat, status, style, teamMain, s
}
// TODO: move this to a separate function
let icon = 'channel-private';
let icon: TIconsName = 'channel-private';
if (teamMain) {
icon = `teams${type === 'p' ? '-private' : ''}`;
} else if (type === 'discussion') {
@ -61,7 +61,7 @@ const RoomTypeIcon = React.memo(({ type, isGroupChat, status, style, teamMain, s
}
}
return <CustomIcon name={icon} size={size} style={iconStyle} />;
return <CustomIcon name={icon} size={size} color={color} style={iconStyle} />;
});
export default RoomTypeIcon;

View File

@ -4,7 +4,7 @@ import Touchable from 'react-native-platform-touchable';
import { themes } from '../lib/constants';
import I18n from '../i18n';
import { CustomIcon } from '../lib/Icons';
import { CustomIcon } from './CustomIcon';
import TextInput from '../presentation/TextInput';
import { useTheme } from '../theme';
import { isIOS } from '../utils/deviceInfo';

View File

@ -1,13 +1,13 @@
import React from 'react';
import { StyleProp, TextStyle } from 'react-native';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon, IconSet, TIconsName } from '../CustomIcon';
import { STATUS_COLORS } from '../../lib/constants';
import { IStatus } from './definition';
const Status = React.memo(({ style, status = 'offline', size = 32, ...props }: Omit<IStatus, 'id'>) => {
const name = `status-${status}`;
const isNameValid = CustomIcon.hasIcon(name);
const name: TIconsName = `status-${status}`;
const isNameValid = IconSet.hasIcon(name);
const iconName = isNameValid ? name : 'status-offline';
const calculatedStyle: StyleProp<TextStyle> = [
{

View File

@ -5,7 +5,7 @@ import Touchable from 'react-native-platform-touchable';
import sharedStyles from '../views/Styles';
import TextInput from '../presentation/TextInput';
import { themes } from '../lib/constants';
import { CustomIcon } from '../lib/Icons';
import { CustomIcon, TIconsName } from './CustomIcon';
import ActivityIndicator from './ActivityIndicator';
import { testProps } from '../lib/methods/testProps';
import { TSupportedThemes } from '../theme';
@ -60,8 +60,8 @@ export interface IRCTextInputProps extends TextInputProps {
inputStyle?: StyleProp<TextStyle>;
inputRef?: React.Ref<RNTextInput>;
testID?: string;
iconLeft?: string;
iconRight?: string;
iconLeft?: TIconsName;
iconRight?: TIconsName;
left?: JSX.Element;
onIconRightPress?(): void;
theme: TSupportedThemes;
@ -83,23 +83,24 @@ export default class RCTextInput extends React.PureComponent<IRCTextInputProps,
get iconLeft() {
const { testID, iconLeft, theme } = this.props;
return (
return iconLeft ? (
<CustomIcon
name={iconLeft}
{...testProps(testID ? `${testID}-icon-left` : '')}
style={[styles.iconContainer, styles.iconLeft, { color: themes[theme].bodyText }]}
size={20}
color={themes[theme].bodyText}
/>
);
) : null;
}
get iconRight() {
const { iconRight, onIconRightPress, theme } = this.props;
return (
return iconRight ? (
<Touchable onPress={onIconRightPress} style={[styles.iconContainer, styles.iconRight]}>
<CustomIcon name={iconRight} style={{ color: themes[theme].bodyText }} size={20} />
<CustomIcon name={iconRight} size={20} color={themes[theme].bodyText} />
</Touchable>
);
) : null;
}
get iconPassword() {
@ -112,6 +113,7 @@ export default class RCTextInput extends React.PureComponent<IRCTextInputProps,
{...testProps(testID ? `${testID}-icon-right` : '')}
style={{ color: themes[theme].auxiliaryText }}
size={20}
color={themes[theme].auxiliaryText}
/>
</Touchable>
);

View File

@ -2,7 +2,7 @@ import React from 'react';
import { StyleSheet, Text, View, ViewStyle } from 'react-native';
import Touchable from 'react-native-platform-touchable';
import { CustomIcon } from '../lib/Icons';
import { CustomIcon } from './CustomIcon';
import { themes } from '../lib/constants';
import sharedStyles from '../views/Styles';
import { useTheme } from '../theme';

View File

@ -13,9 +13,9 @@ import { useTheme } from '../../theme';
import { themes } from '../../lib/constants';
import Button from '../Button';
import sharedStyles from '../../views/Styles';
import RocketChat from '../../lib/rocketchat';
import styles from './styles';
import { IApplicationState } from '../../definitions';
import { Services } from '../../lib/services';
export const TWO_FACTOR = 'TWO_FACTOR';
@ -63,7 +63,7 @@ const TwoFactor = React.memo(({ isMasterDetail }: { isMasterDetail: boolean }) =
const method = data.method ? methods[data.method] : null;
const isEmail = data.method === 'email';
const sendEmail = () => RocketChat.sendEmailCode();
const sendEmail = () => Services.sendEmailCode();
useDeepCompareEffect(() => {
if (!isEmpty(data)) {

View File

@ -9,7 +9,7 @@ import Button from '../Button';
import { textParser } from './utils';
import { themes } from '../../lib/constants';
import sharedStyles from '../../views/Styles';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import { isAndroid } from '../../utils/deviceInfo';
import { useTheme } from '../../theme';
import ActivityIndicator from '../ActivityIndicator';

View File

@ -5,7 +5,7 @@ import FastImage from '@rocket.chat/react-native-fast-image';
import { themes } from '../../../lib/constants';
import { textParser } from '../utils';
import { CustomIcon } from '../../../lib/Icons';
import { CustomIcon } from '../../CustomIcon';
import styles from './styles';
import { IItemData } from '.';
import { TSupportedThemes } from '../../../theme';

View File

@ -2,7 +2,7 @@ import React from 'react';
import { Text, View } from 'react-native';
import Touchable from 'react-native-platform-touchable';
import { CustomIcon } from '../../../lib/Icons';
import { CustomIcon } from '../../CustomIcon';
import { themes } from '../../../lib/constants';
import ActivityIndicator from '../../ActivityIndicator';
import styles from './styles';

View File

@ -3,7 +3,7 @@ import { FlatList, StyleSheet, Text } from 'react-native';
import Popover from 'react-native-popover-view';
import Touchable from 'react-native-platform-touchable';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import ActivityIndicator from '../ActivityIndicator';
import { themes } from '../../lib/constants';
import { useTheme } from '../../theme';

View File

@ -4,7 +4,7 @@ import RNPickerSelect from 'react-native-picker-select';
import sharedStyles from '../../views/Styles';
import { themes } from '../../lib/constants';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import { textParser } from './utils';
import { isAndroid, isIOS } from '../../utils/deviceInfo';
import ActivityIndicator from '../ActivityIndicator';

View File

@ -2,7 +2,7 @@ import React from 'react';
import { Pressable, StyleProp, StyleSheet, Text, View, ViewStyle } from 'react-native';
import Avatar from './Avatar';
import { CustomIcon } from '../lib/Icons';
import { CustomIcon, TIconsName } from './CustomIcon';
import sharedStyles from '../views/Styles';
import { themes } from '../lib/constants';
import { isIOS } from '../utils/deviceInfo';
@ -46,7 +46,7 @@ interface IUserItem {
testID: string;
onLongPress?: () => void;
style?: StyleProp<ViewStyle>;
icon?: string | null;
icon?: TIconsName | null;
theme: TSupportedThemes;
}
@ -71,7 +71,7 @@ const UserItem = ({ name, username, onPress, testID, onLongPress, style, icon, t
@{username}
</Text>
</View>
{icon ? <CustomIcon name={icon} size={22} style={[styles.icon, { color: themes[theme].actionTintColor }]} /> : null}
{icon ? <CustomIcon name={icon} size={22} color={themes[theme].actionTintColor} style={styles.icon} /> : null}
</View>
</Pressable>
);

View File

@ -9,7 +9,7 @@ import { Sound } from 'expo-av/build/Audio/Sound';
import Touchable from './Touchable';
import Markdown from '../markdown';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import sharedStyles from '../../views/Styles';
import { themes } from '../../lib/constants';
import { isAndroid, isIOS } from '../../utils/deviceInfo';

View File

@ -2,7 +2,7 @@ import React, { useContext } from 'react';
import { Text, View } from 'react-native';
import Touchable from './Touchable';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import styles from './styles';
import { BUTTON_HIT_SLOP } from './utils';
import I18n from '../../i18n';

View File

@ -5,7 +5,7 @@ import Touchable from './Touchable';
import { BUTTON_HIT_SLOP } from './utils';
import styles from './styles';
import I18n from '../../i18n';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import { themes } from '../../lib/constants';
import { IMessageCallButton } from './interfaces';
import { useTheme } from '../../theme';

View File

@ -6,7 +6,7 @@ import { StyleSheet, Text, View } from 'react-native';
import { themes } from '../../../../lib/constants';
import { IAttachment } from '../../../../definitions/IAttachment';
import { TGetCustomEmoji } from '../../../../definitions/IEmoji';
import { CustomIcon } from '../../../../lib/Icons';
import { CustomIcon } from '../../../CustomIcon';
import { useTheme } from '../../../../theme';
import sharedStyles from '../../../../views/Styles';
import Markdown from '../../../markdown';

View File

@ -5,7 +5,7 @@ import Touchable from './Touchable';
import { BUTTON_HIT_SLOP, formatMessageCount } from './utils';
import styles from './styles';
import I18n from '../../i18n';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import { DISCUSSION } from './constants';
import { themes } from '../../lib/constants';
import MessageContext from './Context';

View File

@ -1,7 +1,7 @@
import React, { useContext } from 'react';
import Touchable from './Touchable';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import { BUTTON_HIT_SLOP } from './utils';
import MessageContext from './Context';
import styles from './styles';

View File

@ -1,7 +1,7 @@
import React, { useContext } from 'react';
import Touchable from './Touchable';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import styles from './styles';
import { BUTTON_HIT_SLOP } from './utils';
import { themes } from '../../lib/constants';

View File

@ -2,7 +2,7 @@ import React, { useContext } from 'react';
import { Text, View } from 'react-native';
import Touchable from './Touchable';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import styles from './styles';
import Emoji from './Emoji';
import { BUTTON_HIT_SLOP } from './utils';

View File

@ -1,7 +1,7 @@
import React from 'react';
import { themes } from '../../lib/constants';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import styles from './styles';
import { useTheme } from '../../theme';

View File

@ -1,7 +1,7 @@
import React, { memo, useEffect, useState } from 'react';
import { View } from 'react-native';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import styles from './styles';
import { themes } from '../../lib/constants';
import I18n from '../../i18n';

View File

@ -5,7 +5,7 @@ import { dequal } from 'dequal';
import Touchable from './Touchable';
import Markdown from '../markdown';
import { isIOS } from '../../utils/deviceInfo';
import { CustomIcon } from '../../lib/Icons';
import { CustomIcon } from '../CustomIcon';
import { themes } from '../../lib/constants';
import MessageContext from './Context';
import { fileDownload } from '../../utils/fileDownload';

View File

@ -5,11 +5,10 @@ import { Subscription } from 'rxjs';
import Message from './Message';
import MessageContext from './Context';
import debounce from '../../utils/debounce';
import { SYSTEM_MESSAGES, getMessageTranslation } from './utils';
import { getMessageTranslation } from './utils';
import { TSupportedThemes, withTheme } from '../../theme';
import openLink from '../../utils/openLink';
import { TGetCustomEmoji } from '../../definitions/IEmoji';
import { IAttachment, TAnyMessageModel } from '../../definitions';
import { IAttachment, TAnyMessageModel, TGetCustomEmoji } from '../../definitions';
import { IRoomInfoParam } from '../../views/SearchMessagesView';
import { E2E_MESSAGE_TYPE, E2E_STATUS, messagesStatus } from '../../lib/constants';
@ -31,6 +30,7 @@ interface IMessageContainerProps {
Message_GroupingPeriod?: number;
isReadReceiptEnabled?: boolean;
isThreadRoom: boolean;
isSystemMessage?: boolean;
useRealName?: boolean;
autoTranslateRoom?: boolean;
autoTranslateLanguage?: string;
@ -254,9 +254,12 @@ class MessageContainer extends React.Component<IMessageContainerProps, IMessageC
return t === E2E_MESSAGE_TYPE && e2e !== E2E_STATUS.DONE;
}
get isInfo(): boolean {
get isInfo(): string | boolean {
const { item } = this.props;
return (item.t && SYSTEM_MESSAGES.includes(item.t)) ?? false;
if (['e2e', 'discussion-created'].includes(item.t)) {
return false;
}
return item.t;
}
get isTemp(): boolean {

View File

@ -45,7 +45,7 @@ export interface IMessageCallButton {
export interface IMessageContent {
_id: string;
isTemp: boolean;
isInfo: boolean;
isInfo: string | boolean;
tmid?: string;
isThreadRoom: boolean;
msg?: string;
@ -76,7 +76,7 @@ export interface IMessageThread extends Pick<IThread, 'msg' | 'tcount' | 'tlm' |
export interface IMessageTouchable {
hasError: boolean;
isInfo: boolean;
isInfo: string | boolean;
isThreadReply: boolean;
isTemp: boolean;
archived?: boolean;
@ -110,7 +110,7 @@ export interface IMessageInner
export interface IMessage extends IMessageRepliedThread, IMessageInner, IMessageAvatar {
isThreadReply: boolean;
isThreadSequential: boolean;
isInfo: boolean;
isInfo: string | boolean;
isTemp: boolean;
isHeader: boolean;
hasError: boolean;

View File

@ -1,3 +1,4 @@
/* eslint-disable complexity */
import { TMessageModel } from '../../definitions/IMessage';
import I18n from '../../i18n';
import { DISCUSSION } from './constants';
@ -56,10 +57,25 @@ export const SYSTEM_MESSAGES = [
'user-converted-to-channel',
'user-deleted-room-from-team',
'user-removed-room-from-team',
'room-disallowed-reacting',
'room-allowed-reacting',
'room-set-read-only',
'room-removed-read-only',
'omnichannel_placed_chat_on_hold',
'omnichannel_on_hold_chat_resumed'
];
export const IGNORED_LIVECHAT_SYSTEM_MESSAGES = [
'livechat_navigation_history',
'livechat_transcript_history',
'livechat_transfer_history',
'command',
'livechat-close',
'livechat-started',
'livechat_video_call',
'livechat_webrtc_video_call'
];
export const SYSTEM_MESSAGE_TYPES = {
MESSAGE_REMOVED: 'rm',
MESSAGE_PINNED: 'message_pinned',
@ -77,7 +93,15 @@ export const SYSTEM_MESSAGE_TYPES = {
DELETED_ROOM_FROM_TEAM: 'user-deleted-room-from-team',
REMOVED_ROOM_FROM_TEAM: 'user-removed-room-from-team',
OMNICHANNEL_PLACED_CHAT_ON_HOLD: 'omnichannel_placed_chat_on_hold',
OMNICHANNEL_ON_HOLD_CHAT_RESUMED: 'omnichannel_on_hold_chat_resumed'
OMNICHANNEL_ON_HOLD_CHAT_RESUMED: 'omnichannel_on_hold_chat_resumed',
LIVECHAT_NAVIGATION_HISTORY: 'livechat_navigation_history',
LIVECHAT_TRANSCRIPT_HISTORY: 'livechat_transcript_history',
COMMAND: 'command',
LIVECHAT_STARTED: 'livechat-started',
LIVECHAT_CLOSE: 'livechat-close',
LIVECHAT_VIDEO_CALL: 'livechat_video_call',
LIVECHAT_WEBRTC_VIDEO_CALL: 'livechat_webrtc_video_call',
LIVECHAT_TRANSFER_HISTORY: 'livechat_transfer_history'
};
export const SYSTEM_MESSAGE_TYPES_WITH_AUTHOR_NAME = [
@ -95,7 +119,15 @@ export const SYSTEM_MESSAGE_TYPES_WITH_AUTHOR_NAME = [
SYSTEM_MESSAGE_TYPES.CONVERTED_TO_TEAM,
SYSTEM_MESSAGE_TYPES.CONVERTED_TO_CHANNEL,
SYSTEM_MESSAGE_TYPES.DELETED_ROOM_FROM_TEAM,
SYSTEM_MESSAGE_TYPES.REMOVED_ROOM_FROM_TEAM
SYSTEM_MESSAGE_TYPES.REMOVED_ROOM_FROM_TEAM,
SYSTEM_MESSAGE_TYPES.LIVECHAT_NAVIGATION_HISTORY,
SYSTEM_MESSAGE_TYPES.LIVECHAT_TRANSCRIPT_HISTORY,
SYSTEM_MESSAGE_TYPES.COMMAND,
SYSTEM_MESSAGE_TYPES.LIVECHAT_STARTED,
SYSTEM_MESSAGE_TYPES.LIVECHAT_CLOSE,
SYSTEM_MESSAGE_TYPES.LIVECHAT_VIDEO_CALL,
SYSTEM_MESSAGE_TYPES.LIVECHAT_WEBRTC_VIDEO_CALL,
SYSTEM_MESSAGE_TYPES.LIVECHAT_TRANSFER_HISTORY
];
type TInfoMessage = {
@ -108,6 +140,7 @@ type TInfoMessage = {
export const getInfoMessage = ({ type, role, msg, author, comment }: TInfoMessage): string => {
const { username } = author;
if (type === 'rm') {
return I18n.t('Message_removed');
}
@ -198,13 +231,37 @@ export const getInfoMessage = ({ type, role, msg, author, comment }: TInfoMessag
if (type === 'user-removed-room-from-team') {
return I18n.t('Removed__roomName__from_this_team', { roomName: msg });
}
if (type === 'room-disallowed-reacting') {
return I18n.t('Room_disallowed_reacting', { userBy: username });
}
if (type === 'room-allowed-reacting') {
return I18n.t('Room_allowed_reacting', { userBy: username });
}
if (type === 'room-set-read-only') {
return I18n.t('Room_set_read_only', { userBy: username });
}
if (type === 'room-removed-read-only') {
return I18n.t('Room_removed_read_only', { userBy: username });
}
if (type === 'omnichannel_placed_chat_on_hold') {
return I18n.t('Omnichannel_placed_chat_on_hold', { comment });
}
if (type === 'omnichannel_on_hold_chat_resumed') {
return I18n.t('Omnichannel_on_hold_chat_resumed', { comment });
}
return '';
if (type === 'command') {
return I18n.t('Livechat_transfer_return_to_the_queue');
}
if (type === 'livechat-started') {
return I18n.t('Chat_started');
}
if (type === 'livechat-close') {
return I18n.t('Conversation_closed');
}
if (type === 'livechat_transfer_history') {
return I18n.t('New_chat_transfer', { agent: username });
}
return I18n.t('Unsupported_system_message');
};
export const getMessageTranslation = (message: TMessageModel, autoTranslateLanguage: string) => {

View File

@ -0,0 +1,4 @@
export interface IAssetsFavicon512 {
url?: string;
defaultUrl: string;
}

View File

@ -1,23 +1,3 @@
export interface IDepartment {
_id: string;
enabled: boolean;
name: string;
description: string;
showOnRegistration: boolean;
showOnOfflineForm: boolean;
requestTagBeforeClosingChat: boolean;
email: string;
chatClosingTags: string[];
offlineMessageChannelName: string;
maxNumberSimultaneousChat: number;
abandonedRoomsCloseCustomMessage: string;
waitingQueueMessage: string;
departmentsAllowedToForward: string;
_updatedAt: Date;
numAgents: number;
ancestors: string[];
}
export interface ICannedResponse {
_id: string;
shortcut: string;

View File

@ -1,11 +0,0 @@
import Model from '@nozbe/watermelondb/Model';
export interface ICustomEmoji {
_id: string;
name?: string;
aliases?: string[];
extension: string;
_updatedAt: Date;
}
export type TCustomEmojiModel = ICustomEmoji & Model;

View File

@ -0,0 +1,4 @@
import { TSubscriptionModel } from './ISubscription';
export type TDataSelect = Pick<TSubscriptionModel, 'rid'> &
Partial<Pick<TSubscriptionModel, 't' | 'name' | 'teamMain' | 'alert'>>;

View File

@ -1,31 +1,43 @@
// TODO: evaluate unification with IEmoji
import Model from '@nozbe/watermelondb/Model';
import { StyleProp } from 'react-native';
import { ImageStyle } from '@rocket.chat/react-native-fast-image';
export interface IEmoji {
content?: string;
name?: string;
extension?: string;
isCustom?: boolean;
content: string;
name: string;
extension: string;
isCustom: boolean;
count?: number;
}
export interface ICustomEmojis {
[key: string]: Pick<IEmoji, 'name' | 'extension'>;
}
export interface ICustomEmoji {
baseUrl?: string;
emoji: IEmoji;
style: any;
style: StyleProp<ImageStyle>;
}
export interface ICustomEmojiModel {
_id: string;
name?: string;
aliases?: string[];
extension: string;
_updatedAt: Date;
}
export interface IEmojiCategory {
baseUrl: string;
emojis: IEmoji[];
onEmojiSelected: Function;
emojisPerRow: number;
width: number;
style: any;
onEmojiSelected: (emoji: IEmoji) => void;
width: number | null;
style: StyleProp<ImageStyle>;
tabLabel: string;
}
// TODO: copied from reducers/customEmojis. We can unify later.
export interface IReduxEmoji {
name: string;
extension: any;
}
export type TGetCustomEmoji = (name: string) => any;
export type TFrequentlyUsedEmojiModel = IEmoji & Model;
export type TCustomEmojiModel = ICustomEmojiModel & Model;

View File

@ -1,11 +0,0 @@
import Model from '@nozbe/watermelondb/Model';
// TODO: evaluate unification with IEmoji
export interface IFrequentlyUsedEmoji {
content?: string;
extension?: string;
isCustom: boolean;
count: number;
}
export type TFrequentlyUsedEmojiModel = IFrequentlyUsedEmoji & Model;

View File

@ -13,6 +13,11 @@ export interface ILivechatDepartment {
_updatedAt?: Date;
businessHourId?: string;
fallbackForwardDepartment?: string;
maxNumberSimultaneousChat: number;
abandonedRoomsCloseCustomMessage: string;
waitingQueueMessage: string;
departmentsAllowedToForward: string;
ancestors: string[];
// extra optional fields
[k: string]: any;
}

View File

@ -0,0 +1,31 @@
import React from 'react';
export interface IProfileParams {
name: string;
username: string;
email: string | null;
newPassword: string;
currentPassword: string;
}
export interface IAvatarButton {
key: string;
child: React.ReactNode;
onPress: () => void;
disabled: boolean;
}
export interface IAvatar {
data: {} | string | null;
url?: string;
contentType?: string;
service?: any;
}
export interface IAvatarSuggestion {
[service: string]: {
url: string;
blob: string;
contentType: string;
};
}

View File

@ -1,69 +0,0 @@
import { StackNavigationProp } from '@react-navigation/stack';
import React from 'react';
import { TSupportedThemes } from '../theme';
import { ProfileStackParamList } from '../stacks/types';
import { IUser } from './IUser';
export interface IParams {
name: string;
username: string;
email: string | null;
newPassword: string;
currentPassword: string;
}
export interface IAvatarButton {
key: string;
child: React.ReactNode;
onPress: () => void;
disabled: boolean;
}
export interface INavigationOptions {
navigation: StackNavigationProp<ProfileStackParamList, 'ProfileView'>;
isMasterDetail?: boolean;
}
export interface IProfileViewProps {
user: IUser;
baseUrl: string;
Accounts_AllowEmailChange: boolean;
Accounts_AllowPasswordChange: boolean;
Accounts_AllowRealNameChange: boolean;
Accounts_AllowUserAvatarChange: boolean;
Accounts_AllowUsernameChange: boolean;
Accounts_CustomFields: string;
setUser: Function;
theme: TSupportedThemes;
}
export interface IAvatar {
data: {} | string | null;
url?: string;
contentType?: string;
service?: any;
}
export interface IAvatarSuggestion {
[service: string]: {
url: string;
blob: string;
contentType: string;
};
}
export interface IProfileViewState {
saving: boolean;
name: string;
username: string;
email: string | null;
newPassword: string | null;
currentPassword: string | null;
avatarUrl: string | null;
avatar: IAvatar;
avatarSuggestions: IAvatarSuggestion;
customFields: {
[key: string | number]: string;
};
}

View File

@ -142,6 +142,11 @@ export interface IServerRoom extends IRocketChatRecord {
encrypted?: boolean;
topic?: any;
username?: string;
nickname?: string;
federation?: any;
roomsCount?: number;
u: Pick<IUser, '_id' | 'username' | 'name'>;
uids: Array<string>;
@ -205,9 +210,12 @@ export interface IServerRoom extends IRocketChatRecord {
departmentId?: string;
livechatData?: any;
tags?: string[];
isLastOwner?: boolean;
}
export interface IRoomNotifications {
[key: string]: any;
disableNotifications?: boolean;
muteGroupMentions?: boolean;
hideUnreadStatus?: boolean;
@ -216,3 +224,5 @@ export interface IRoomNotifications {
mobilePushNotifications?: TNotifications;
emailNotifications?: TNotifications;
}
export type TRoomNotificationsModel = IRoomNotifications & Model;

View File

@ -6,7 +6,7 @@ export interface ISearchLocal {
name: string;
t: string;
fname: string;
encrypted: boolean | null;
encrypted: boolean;
lastMessage?: ILastMessage;
}

View File

@ -12,8 +12,7 @@ export * from './IRoom';
export * from './IMessage';
export * from './IThread';
export * from './IThreadMessage';
export * from './ICustomEmoji';
export * from './IFrequentlyUsedEmoji';
export * from './IEmoji';
export * from './IUpload';
export * from './ISettings';
export * from './IRole';
@ -29,6 +28,7 @@ export * from './IUrl';
export * from './ICredentials';
export * from './ISearch';
export * from './TUserStatus';
export * from './IProfile';
export interface IBaseScreen<T extends Record<string, object | undefined>, S extends string> {
navigation: StackNavigationProp<T, S>;

View File

@ -1,8 +1,8 @@
import { NavigatorScreenParams } from '@react-navigation/core';
import { StackNavigationOptions } from '@react-navigation/stack';
import { ISubscription } from './ISubscription';
import { IServer } from './IServer';
import { TSubscriptionModel } from './ISubscription';
import { TServerModel } from './IServer';
import { IAttachment } from './IAttachment';
import { MasterDetailInsideStackParamList } from '../stacks/MasterDetailStack/types';
import { OutsideParamList, InsideStackParamList } from '../stacks/types';
@ -37,10 +37,10 @@ export type ShareInsideStackParamList = {
attachments: IAttachment[];
isShareView?: boolean;
isShareExtension: boolean;
serverInfo: IServer;
serverInfo: TServerModel;
text: string;
room: ISubscription;
thread: any; // TODO: Change
room: TSubscriptionModel;
thread?: any; // TODO: Change
};
SelectServerView: undefined;
};

View File

@ -1,4 +1,4 @@
import { IParams } from '../../IProfileViewInterfaces';
import { IProfileParams } from '../../IProfile';
import type { ITeam } from '../../ITeam';
import type { IUser } from '../../IUser';
import { INotificationPreferences, IUserPreferences, IUserRegistered } from '../../IUser';
@ -39,7 +39,10 @@ export type UsersEndpoints = {
POST: (params: { status: string; message: string }) => {};
};
'users.updateOwnBasicInfo': {
POST: (params: { data: IParams | Pick<IParams, 'username'>; customFields?: { [key: string | number]: string } }) => {
POST: (params: {
data: IProfileParams | Pick<IProfileParams, 'username'>;
customFields?: { [key: string | number]: string };
}) => {
user: IUser;
};
};

View File

@ -3,7 +3,7 @@ import { View, Text } from 'react-native';
import { useTheme } from '../../../../theme';
import { themes } from '../../../../lib/constants';
import { CustomIcon } from '../../../../lib/Icons';
import { CustomIcon } from '../../../../containers/CustomIcon';
import * as List from '../../../../containers/List';
import styles from './styles';
import UnreadBadge from '../../../../containers/UnreadBadge';

View File

@ -5,12 +5,12 @@ import * as List from '../../../../containers/List';
import styles from './styles';
import { SWITCH_TRACK_COLOR, themes } from '../../../../lib/constants';
import { useTheme } from '../../../../theme';
import RocketChat from '../../../../lib/rocketchat';
import { IUser } from '../../../../definitions/IUser';
import { showConfirmationAlert } from '../../../../utils/info';
import I18n from '../../../../i18n';
import { changeLivechatStatus, isOmnichannelStatusAvailable } from '../../lib';
import OmnichannelQueue from './OmnichannelQueue';
import { isOmnichannelModuleAvailable } from '../../../../lib/methods';
interface IOmnichannelStatus {
searching: boolean;
@ -28,7 +28,7 @@ const OmnichannelStatus = memo(({ searching, goQueue, queueSize, user }: IOmnich
setStatus(isOmnichannelStatusAvailable(user));
}, [user.statusLivechat]);
if (searching || !(RocketChat.isOmnichannelModuleAvailable() && user?.roles?.includes('livechat-agent'))) {
if (searching || !(isOmnichannelModuleAvailable() && user?.roles?.includes('livechat-agent'))) {
return null;
}

View File

@ -1,9 +1,10 @@
import log from '../../../../utils/log';
import { store } from '../../../../lib/store/auxStore';
import RocketChat from '../../../../lib/rocketchat';
import { inquiryQueueAdd, inquiryQueueRemove, inquiryQueueUpdate, inquiryRequest } from '../../actions/inquiry';
import sdk from '../../../../lib/services/sdk';
import { IOmnichannelRoom } from '../../../../definitions';
import { hasRole } from '../../../../lib/methods';
import { Services } from '../../../../lib/services';
interface IArgsQueueOmnichannel extends IOmnichannelRoom {
type: string;
@ -81,11 +82,11 @@ export default function subscribeInquiry() {
throw new Error('inquiry: @subscribeInquiry user.id not found');
}
RocketChat.getAgentDepartments(user.id).then(result => {
Services.getAgentDepartments(user.id).then(result => {
if (result.success) {
const { departments } = result;
if (!departments.length || RocketChat.hasRole('livechat-manager')) {
if (!departments.length || hasRole('livechat-manager')) {
sdk.subscribe(streamTopic, 'public').catch((e: unknown) => console.log(e));
}

View File

@ -1,14 +1,14 @@
import { put, select, takeLatest } from 'redux-saga/effects';
import * as types from '../../../actions/actionsTypes';
import RocketChat from '../../../lib/rocketchat';
import { Services } from '../../../lib/services';
import EventEmitter from '../../../utils/events';
import { inquiryFailure, inquirySetEnabled, inquirySuccess } from '../actions/inquiry';
import { getInquiriesQueued, isOmnichannelStatusAvailable } from '../lib';
const handleRequest = function* handleRequest() {
try {
const routingConfig = yield RocketChat.getRoutingConfig();
const routingConfig = yield Services.getRoutingConfig();
const user = yield select(state => state.login.user);
// if routingConfig showQueue is enabled and omnichannel is enabled
const showQueue = routingConfig.showQueue && isOmnichannelStatusAvailable(user);

View File

@ -15,7 +15,6 @@ import SafeAreaView from '../../../containers/SafeAreaView';
import StatusBar from '../../../containers/StatusBar';
import { goRoom } from '../../../utils/goRoom';
import * as HeaderButton from '../../../containers/HeaderButton';
import RocketChat from '../../../lib/rocketchat';
import { events, logEvent } from '../../../utils/log';
import { getInquiryQueueSelector } from '../selectors/inquiry';
import { IOmnichannelRoom, IApplicationState } from '../../../definitions';
@ -23,6 +22,7 @@ import { DisplayMode, MAX_SIDEBAR_WIDTH, themes } from '../../../lib/constants';
import { ChatsStackParamList } from '../../../stacks/types';
import { MasterDetailInsideStackParamList } from '../../../stacks/MasterDetailStack/types';
import { TSettingsValues } from '../../../reducers/settings';
import { getRoomAvatar, getRoomTitle, getUidDirectMessage } from '../../../lib/methods';
interface INavigationOptions {
isMasterDetail: boolean;
@ -98,12 +98,6 @@ class QueueListView extends React.Component<IQueueListView, any> {
});
};
getRoomTitle = (item: IOmnichannelRoom) => RocketChat.getRoomTitle(item);
getRoomAvatar = (item: IOmnichannelRoom) => RocketChat.getRoomAvatar(item);
getUidDirectMessage = (room: IOmnichannelRoom) => RocketChat.getUidDirectMessage(room);
renderItem: ListRenderItem<IOmnichannelRoom> = ({ item }) => {
const {
user: { id: userId, username, token },
@ -115,7 +109,7 @@ class QueueListView extends React.Component<IQueueListView, any> {
showAvatar,
displayMode
} = this.props;
const id = this.getUidDirectMessage(item);
const id = getUidDirectMessage(item);
return (
<RoomItem
@ -131,8 +125,8 @@ class QueueListView extends React.Component<IQueueListView, any> {
testID={`queue-list-view-item-${item.name}`}
width={isMasterDetail ? MAX_SIDEBAR_WIDTH : width}
useRealName={useRealName}
getRoomTitle={this.getRoomTitle}
getRoomAvatar={this.getRoomAvatar}
getRoomTitle={getRoomTitle}
getRoomAvatar={getRoomAvatar}
visitor={item.v}
swipeEnabled={false}
showAvatar={showAvatar}

View File

@ -132,6 +132,7 @@
"Channel_Name": "Channel Name",
"Channels": "Channels",
"Chats": "Chats",
"Chat_started": "Chat started",
"Call_already_ended": "Call already ended!",
"Clear_cookies_alert": "Do you want to clear all cookies?",
"Clear_cookies_desc": "This action will clear all login cookies, allowing you to login into other accounts.",
@ -149,6 +150,7 @@
"Choose_where_you_want_links_be_opened": "Choose where you want links be opened",
"Code": "Code",
"Code_or_password_invalid": "Code or password invalid",
"Conversation_closed": "Conversation closed",
"Collaborative": "Collaborative",
"Confirm": "Confirm",
"Connect": "Connect",
@ -301,6 +303,7 @@
"License": "License",
"Livechat": "Livechat",
"Livechat_edit": "Livechat edit",
"Livechat_transfer_return_to_the_queue": "returned the chat to the queue",
"Login": "Login",
"Login_error": "Your credentials were rejected! Please try again.",
"Login_with": "Login with",
@ -334,6 +337,7 @@
"N_channels": "{{n}} channels",
"Name": "Name",
"Never": "Never",
"New_chat_transfer": "New Chat Transfer: {{agent}} returned the chat to the queue",
"New_Message": "New Message",
"New_Password": "New Password",
"New_Server": "New Server",
@ -449,6 +453,10 @@
"Room_Info": "Room Info",
"Room_Members": "Room Members",
"Room_name_changed": "Room name changed to: {{name}} by {{userBy}}",
"Room_disallowed_reacting": "Room disallowed reacting by {{userBy}}",
"Room_allowed_reacting": "Room allowed reacting by {{userBy}}",
"Room_set_read_only": "Room set read only by {{userBy}}",
"Room_removed_read_only": "Room removed read only by {{userBy}}",
"SAVE": "SAVE",
"Save_Changes": "Save Changes",
"Save": "Save",
@ -547,6 +555,7 @@
"Unread": "Unread",
"Unread_on_top": "Unread on top",
"Unstar": "Unstar",
"Unsupported_system_message": "Unsupported system message",
"Updating": "Updating...",
"Uploading": "Uploading",
"Upload_file_question_mark": "Upload file?",

View File

@ -1,36 +1,36 @@
import React from 'react';
import { Dimensions, Linking } from 'react-native';
import { AppearanceProvider } from 'react-native-appearance';
import { Provider } from 'react-redux';
import { KeyCommandsEmitter } from 'react-native-keycommands';
import { initialWindowMetrics, SafeAreaProvider } from 'react-native-safe-area-context';
import RNScreens from 'react-native-screens';
import { SafeAreaProvider, initialWindowMetrics } from 'react-native-safe-area-context';
import { Provider } from 'react-redux';
import { getTheme, initialTheme, newThemeState, subscribeTheme, unsubscribeTheme } from './utils/theme';
import EventEmitter from './utils/events';
import { appInit, appInitLocalSettings, setMasterDetail as setMasterDetailAction } from './actions/app';
import { deepLinkingOpen } from './actions/deepLinking';
import AppContainer from './AppContainer';
import { KEY_COMMAND } from './commands';
import { ActionSheetProvider } from './containers/ActionSheet';
import InAppNotification from './containers/InAppNotification';
import Toast from './containers/Toast';
import TwoFactor from './containers/TwoFactor';
import { ICommand } from './definitions/ICommand';
import { IThemePreference } from './definitions/ITheme';
import { DimensionsContext } from './dimensions';
import { colors, isFDroidBuild, MIN_WIDTH_MASTER_DETAIL_LAYOUT, themes } from './lib/constants';
import { getAllowAnalyticsEvents, getAllowCrashReport } from './lib/methods';
import parseQuery from './lib/methods/helpers/parseQuery';
import { initializePushNotifications, onNotification } from './lib/notifications';
import { toggleAnalyticsEventsReport, toggleCrashErrorsReport } from './utils/log';
import { ThemeContext, TSupportedThemes } from './theme';
import { DimensionsContext } from './dimensions';
import RocketChat from './lib/rocketchat';
import { isTablet } from './utils/deviceInfo';
import { KEY_COMMAND } from './commands';
import AppContainer from './AppContainer';
import TwoFactor from './containers/TwoFactor';
import ScreenLockedView from './views/ScreenLockedView';
import ChangePasscodeView from './views/ChangePasscodeView';
import Toast from './containers/Toast';
import InAppNotification from './containers/InAppNotification';
import { ActionSheetProvider } from './containers/ActionSheet';
import debounce from './utils/debounce';
import { isFDroidBuild, MIN_WIDTH_MASTER_DETAIL_LAYOUT, colors, themes } from './lib/constants';
import { IThemePreference } from './definitions/ITheme';
import { ICommand } from './definitions/ICommand';
import store from './lib/store';
import { initStore } from './lib/store/auxStore';
import { ThemeContext, TSupportedThemes } from './theme';
import debounce from './utils/debounce';
import { isTablet } from './utils/deviceInfo';
import EventEmitter from './utils/events';
import { toggleAnalyticsEventsReport, toggleCrashErrorsReport } from './utils/log';
import { getTheme, initialTheme, newThemeState, subscribeTheme, unsubscribeTheme } from './utils/theme';
import ChangePasscodeView from './views/ChangePasscodeView';
import ScreenLockedView from './views/ScreenLockedView';
RNScreens.enableScreens();
initStore(store);
@ -193,10 +193,10 @@ export default class Root extends React.Component<{}, IState> {
};
initCrashReport = () => {
RocketChat.getAllowCrashReport().then(allowCrashReport => {
getAllowCrashReport().then(allowCrashReport => {
toggleCrashErrorsReport(allowCrashReport);
});
RocketChat.getAllowAnalyticsEvents().then(allowAnalyticsEvents => {
getAllowAnalyticsEvents().then(allowAnalyticsEvents => {
toggleAnalyticsEventsReport(allowAnalyticsEvents);
});
};

View File

@ -1,7 +0,0 @@
import { createIconSetFromIcoMoon } from 'react-native-vector-icons';
import icoMoonConfig from './selection.json';
const CustomIcon = createIconSetFromIcoMoon(icoMoonConfig, 'custom', 'custom.ttf');
export { CustomIcon };

View File

@ -19,3 +19,6 @@ export const THEME_PREFERENCES_KEY = 'RC_THEME_PREFERENCES_KEY';
export const CRASH_REPORT_KEY = 'RC_CRASH_REPORT_KEY';
export const ANALYTICS_EVENTS_KEY = 'RC_ANALYTICS_EVENTS_KEY';
export const MIN_ROCKETCHAT_VERSION = '0.70.0';
export const TOKEN_KEY = 'reactnativemeteor_usertoken';
export const CURRENT_SERVER = 'currentServer';
export const CERTIFICATE_KEY = 'RC_CERTIFICATE_KEY';

View File

@ -3,7 +3,6 @@ import SimpleCrypto from 'react-native-simple-crypto';
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
import { Q, Model } from '@nozbe/watermelondb';
import RocketChat from '../rocketchat';
import UserPreferences from '../methods/userPreferences';
import database from '../database';
import protectedFunction from '../methods/helpers/protectedFunction';
@ -21,6 +20,7 @@ import {
E2E_RANDOM_PASSWORD_KEY,
E2E_STATUS
} from '../constants';
import { Services } from '../services';
class Encryption {
ready: boolean;
@ -141,10 +141,10 @@ class Encryption {
const encodedPrivateKey = await this.encodePrivateKey(EJSON.stringify(privateKey), password, userId);
// Send the new keys to the server
await RocketChat.e2eSetUserPublicAndPrivateKeys(EJSON.stringify(publicKey), encodedPrivateKey);
await Services.e2eSetUserPublicAndPrivateKeys(EJSON.stringify(publicKey), encodedPrivateKey);
// Request e2e keys of all encrypted rooms
await RocketChat.e2eRequestSubscriptionKeys();
await Services.e2eRequestSubscriptionKeys();
};
// Encode a private key before send it to the server
@ -197,7 +197,7 @@ class Encryption {
const publicKey = UserPreferences.getString(`${server}-${E2E_PUBLIC_KEY}`);
// Send the new keys to the server
await RocketChat.e2eSetUserPublicAndPrivateKeys(EJSON.stringify(publicKey), encodedPrivateKey);
await Services.e2eSetUserPublicAndPrivateKeys(EJSON.stringify(publicKey), encodedPrivateKey);
};
// get a encryption room instance

View File

@ -4,7 +4,6 @@ import SimpleCrypto from 'react-native-simple-crypto';
import ByteBuffer from 'bytebuffer';
import { IMessage } from '../../definitions';
import RocketChat from '../rocketchat';
import Deferred from '../../utils/deferred';
import debounce from '../../utils/debounce';
import database from '../database';
@ -22,6 +21,7 @@ import {
import { Encryption } from './index';
import { IUser } from '../../definitions/IUser';
import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../constants';
import { Services } from '../services';
export default class EncryptionRoom {
ready: boolean;
@ -134,7 +134,7 @@ export default class EncryptionRoom {
this.sessionKeyExportedString = EJSON.stringify(sessionKeyExported);
this.keyID = Base64.encode(this.sessionKeyExportedString).slice(0, 12);
await RocketChat.e2eSetRoomKeyID(this.roomId, this.keyID);
await Services.e2eSetRoomKeyID(this.roomId, this.keyID);
await this.encryptRoomKey();
};
@ -147,7 +147,7 @@ export default class EncryptionRoom {
// this will be called again and run once in 5 seconds
requestRoomKey = debounce(
async (e2eKeyId: string) => {
await RocketChat.e2eRequestRoomKey(this.roomId, e2eKeyId);
await Services.e2eRequestRoomKey(this.roomId, e2eKeyId);
},
5000,
true
@ -155,7 +155,7 @@ export default class EncryptionRoom {
// Create an encrypted key for this room based on users
encryptRoomKey = async () => {
const result = await RocketChat.e2eGetUsersOfRoomWithoutKey(this.roomId);
const result = await Services.e2eGetUsersOfRoomWithoutKey(this.roomId);
if (result.success) {
const { users } = result;
await Promise.all(users.map(user => this.encryptRoomKeyForUser(user)));
@ -168,7 +168,7 @@ export default class EncryptionRoom {
const { public_key: publicKey } = user.e2e;
const userKey = await SimpleCrypto.RSA.importKey(EJSON.parse(publicKey));
const encryptedUserKey = await SimpleCrypto.RSA.encrypt(this.sessionKeyExportedString as string, userKey);
await RocketChat.e2eUpdateGroupKey(user?._id, this.roomId, this.keyID + encryptedUserKey);
await Services.e2eUpdateGroupKey(user?._id, this.roomId, this.keyID + encryptedUserKey);
}
};

View File

@ -1,5 +1,4 @@
import { ITriggerAction, IUserInteraction, ModalActions } from '../../containers/UIKit/interfaces';
import { TRocketChat } from '../../definitions/IRocketChat';
import EventEmitter from '../../utils/events';
import fetch from '../../utils/fetch';
import random from '../../utils/random';
@ -82,10 +81,7 @@ export const handlePayloadUserInteraction = (
return ModalActions.CLOSE;
};
export function triggerAction(
this: TRocketChat,
{ type, actionId, appId, rid, mid, viewId, container, ...rest }: ITriggerAction
) {
export function triggerAction({ type, actionId, appId, rid, mid, viewId, container, ...rest }: ITriggerAction) {
return new Promise<ModalActions | undefined | void>(async (resolve, reject) => {
const triggerId = generateTriggerId(appId);

View File

@ -1,8 +1,8 @@
import { ERoomTypes } from '../../definitions';
import { store } from '../store/auxStore';
import database from '../database';
import RocketChat from '../rocketchat';
import sdk from '../services/sdk';
import { Services } from '../services';
const restTypes = {
channel: 'channels',
@ -17,7 +17,7 @@ async function open({ type, rid, name }: { type: ERoomTypes; rid: string; name:
// if it's a direct link without rid we'll create a new dm
// if the dm already exists it'll return the existent
if (type === ERoomTypes.DIRECT && !rid) {
const result = await RocketChat.createDirectMessage(name);
const result = await Services.createDirectMessage(name);
if (result.success) {
const { room } = result;
return {
@ -63,7 +63,7 @@ async function open({ type, rid, name }: { type: ERoomTypes; rid: string; name:
}
}
export default async function canOpenRoom({ rid, path, isCall }: { rid: string; isCall: boolean; path: string }): Promise<any> {
export async function canOpenRoom({ rid, path, isCall }: { rid: string; isCall: boolean; path: string }): Promise<any> {
try {
const db = database.active;
const subsCollection = db.get('subscriptions');

View File

@ -1,6 +1,6 @@
import database from '../database';
export default async function clearCache({ server }: { server: string }): Promise<void> {
export async function clearCache({ server }: { server: string }): Promise<void> {
try {
const serversDB = database.servers;
await serversDB.write(async () => {

View File

@ -0,0 +1,19 @@
import AsyncStorage from '@react-native-community/async-storage';
import { ANALYTICS_EVENTS_KEY, CRASH_REPORT_KEY } from '../constants';
export async function getAllowCrashReport() {
const allowCrashReport = await AsyncStorage.getItem(CRASH_REPORT_KEY);
if (allowCrashReport === null) {
return true;
}
return JSON.parse(allowCrashReport);
}
export async function getAllowAnalyticsEvents() {
const allowAnalyticsEvents = await AsyncStorage.getItem(ANALYTICS_EVENTS_KEY);
if (allowAnalyticsEvents === null) {
return true;
}
return JSON.parse(allowAnalyticsEvents);
}

View File

@ -57,11 +57,6 @@ export function getEnterpriseModules() {
});
}
export function hasLicense(module: string) {
const { enterpriseModules } = reduxStore.getState();
return enterpriseModules.includes(module);
}
export function isOmnichannelModuleAvailable() {
const { enterpriseModules } = reduxStore.getState();
return [LICENSE_OMNICHANNEL_MOBILE_ENTERPRISE, LICENSE_LIVECHAT_ENTERPRISE].some(module => enterpriseModules.includes(module));

View File

@ -1,12 +1,11 @@
import orderBy from 'lodash/orderBy';
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
import { ICustomEmojis } from '../../reducers/customEmojis';
import { store as reduxStore } from '../store/auxStore';
import database from '../database';
import log from '../../utils/log';
import { setCustomEmojis as setCustomEmojisAction } from '../../actions/customEmojis';
import { ICustomEmoji, TCustomEmojiModel } from '../../definitions';
import { ICustomEmojiModel, TCustomEmojiModel, ICustomEmojis } from '../../definitions';
import sdk from '../services/sdk';
import { compareServerVersion } from './helpers/compareServerVersion';
@ -16,7 +15,7 @@ interface IUpdateEmojis {
allRecords: TCustomEmojiModel[];
}
const getUpdatedSince = (allEmojis: ICustomEmoji[]) => {
const getUpdatedSince = (allEmojis: ICustomEmojiModel[]) => {
if (!allEmojis.length) {
return null;
}

View File

@ -2,7 +2,7 @@ import log from '../../utils/log';
import { TMessageModel, TSubscriptionModel } from '../../definitions';
import { store } from '../store/auxStore';
import { isGroupChat } from './helpers';
import getRoom from './getRoom';
import { getRoom } from './getRoom';
type TRoomType = 'p' | 'c' | 'd';

View File

@ -1,7 +1,7 @@
import { TSubscriptionModel } from '../../definitions';
import database from '../database';
export default async function getRoom(rid: string): Promise<TSubscriptionModel> {
export async function getRoom(rid: string): Promise<TSubscriptionModel> {
try {
const db = database.active;
const room = await db.get('subscriptions').find(rid);

View File

@ -1,6 +1,6 @@
import { IServerSubscription, RoomType } from '../../definitions';
import { getSubscriptionByRoomId } from '../database/services/Subscription';
import RocketChat from '../rocketchat';
import { Services } from '../services';
export interface IRoomInfoResult {
rid: IServerSubscription['rid'];
@ -21,7 +21,7 @@ const getRoomInfo = async (rid: string): Promise<IRoomInfoResult | null> => {
};
}
result = await RocketChat.getRoomInfo(rid);
result = await Services.getRoomInfo(rid);
if (result?.success) {
return {
rid,

View File

@ -1,6 +1,6 @@
import sdk from '../services/sdk';
export default function (updatedSince: Date) {
export function getRooms(updatedSince: Date) {
// subscriptions.get: Since RC 0.60.0
// rooms.get: Since RC 0.62.0
if (updatedSince) {

Some files were not shown because too many files have changed in this diff Show More