Merge branch 'develop' into branch.test
This commit is contained in:
commit
5f5e9df33a
|
@ -339,7 +339,7 @@ jobs:
|
|||
lint-testunit:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/node:15
|
||||
- image: cimg/node:16.14
|
||||
resource_class: large
|
||||
environment:
|
||||
CODECOV_TOKEN: caa771ab-3d45-4756-8e2a-e1f25996fef6
|
||||
|
@ -372,7 +372,7 @@ jobs:
|
|||
android-build-experimental:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/android:api-29-node
|
||||
- image: cimg/android:2022.03.1-node
|
||||
environment:
|
||||
<<: *android-env
|
||||
<<: *bash-env
|
||||
|
@ -383,7 +383,7 @@ jobs:
|
|||
android-build-official:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/android:api-29-node
|
||||
- image: cimg/android:2022.03.1-node
|
||||
environment:
|
||||
<<: *android-env
|
||||
<<: *bash-env
|
||||
|
@ -394,7 +394,7 @@ jobs:
|
|||
android-internal-app-sharing-experimental:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/android:api-28-node
|
||||
- image: cimg/android:2022.03.1-node
|
||||
|
||||
steps:
|
||||
- upload-to-internal-app-sharing
|
||||
|
@ -402,7 +402,7 @@ jobs:
|
|||
android-google-play-beta-experimental:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/android:api-29-node
|
||||
- image: cimg/android:2022.03.1-node
|
||||
|
||||
steps:
|
||||
- upload-to-google-play-beta:
|
||||
|
@ -411,14 +411,14 @@ jobs:
|
|||
android-google-play-production-experimental:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/android:api-29-node
|
||||
- image: cimg/android:2022.03.1-node
|
||||
steps:
|
||||
- upload-to-google-play-production
|
||||
|
||||
android-google-play-beta-official:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/android:api-29-node
|
||||
- image: cimg/android:2022.03.1-node
|
||||
|
||||
steps:
|
||||
- upload-to-google-play-beta:
|
||||
|
|
|
@ -144,7 +144,7 @@ android {
|
|||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode VERSIONCODE as Integer
|
||||
versionName "4.26.2"
|
||||
versionName "4.27.0"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
if (!isFoss) {
|
||||
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]
|
||||
|
|
|
@ -28,7 +28,8 @@ const Avatar = React.memo(
|
|||
text,
|
||||
size = 25,
|
||||
borderRadius = 4,
|
||||
type = SubscriptionType.DIRECT
|
||||
type = SubscriptionType.DIRECT,
|
||||
externalProviderUrl
|
||||
}: IAvatar) => {
|
||||
const { theme } = useTheme();
|
||||
|
||||
|
@ -67,7 +68,8 @@ const Avatar = React.memo(
|
|||
avatarETag,
|
||||
serverVersion,
|
||||
rid,
|
||||
blockUnauthenticatedAccess
|
||||
blockUnauthenticatedAccess,
|
||||
externalProviderUrl
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,10 @@ class AvatarContainer extends React.Component<IAvatar, any> {
|
|||
|
||||
shouldComponentUpdate(nextProps: IAvatar, nextState: { avatarETag: string }) {
|
||||
const { avatarETag } = this.state;
|
||||
const { text, type } = this.props;
|
||||
const { text, type, size, externalProviderUrl } = this.props;
|
||||
if (nextProps.externalProviderUrl !== externalProviderUrl) {
|
||||
return true;
|
||||
}
|
||||
if (nextState.avatarETag !== avatarETag) {
|
||||
return true;
|
||||
}
|
||||
|
@ -42,6 +45,10 @@ class AvatarContainer extends React.Component<IAvatar, any> {
|
|||
if (nextProps.type !== type) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.size !== size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -100,6 +107,7 @@ const mapStateToProps = (state: IApplicationState) => ({
|
|||
blockUnauthenticatedAccess:
|
||||
(state.share.settings?.Accounts_AvatarBlockUnauthenticatedAccess as boolean) ??
|
||||
state.settings.Accounts_AvatarBlockUnauthenticatedAccess ??
|
||||
true
|
||||
true,
|
||||
externalProviderUrl: state.settings.Accounts_AvatarExternalProviderUrl as string
|
||||
});
|
||||
export default connect(mapStateToProps)(AvatarContainer);
|
||||
|
|
|
@ -23,4 +23,5 @@ export interface IAvatar {
|
|||
rid?: string;
|
||||
blockUnauthenticatedAccess?: boolean;
|
||||
serverVersion: string | null;
|
||||
externalProviderUrl?: string;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import { CustomIcon } from '../../lib/Icons';
|
|||
import sharedStyles from '../../views/Styles';
|
||||
import { themes } from '../../lib/constants';
|
||||
import { useTheme } from '../../theme';
|
||||
import { ROW_HEIGHT } from '../../presentation/RoomItem';
|
||||
import { ROW_HEIGHT } from '../RoomItem';
|
||||
import { goRoom } from '../../utils/goRoom';
|
||||
import Navigation from '../../lib/navigation/appNavigation';
|
||||
import { useOrientation } from '../../dimensions';
|
||||
|
|
|
@ -6,32 +6,13 @@ import { isRTL } from '../../i18n';
|
|||
import { CustomIcon } from '../../lib/Icons';
|
||||
import { DisplayMode, themes } from '../../lib/constants';
|
||||
import styles, { ACTION_WIDTH, LONG_SWIPE, ROW_HEIGHT_CONDENSED } from './styles';
|
||||
import { TSupportedThemes } from '../../theme';
|
||||
|
||||
interface ILeftActions {
|
||||
theme: TSupportedThemes;
|
||||
transX: any;
|
||||
isRead: boolean;
|
||||
width: number;
|
||||
onToggleReadPress(): void;
|
||||
displayMode: string;
|
||||
}
|
||||
|
||||
interface IRightActions {
|
||||
theme: TSupportedThemes;
|
||||
transX: any;
|
||||
favorite: boolean;
|
||||
width: number;
|
||||
toggleFav(): void;
|
||||
onHidePress(): void;
|
||||
displayMode: string;
|
||||
}
|
||||
import { ILeftActionsProps, IRightActionsProps } from './interfaces';
|
||||
|
||||
const reverse = new Animated.Value(isRTL() ? -1 : 1);
|
||||
const CONDENSED_ICON_SIZE = 24;
|
||||
const EXPANDED_ICON_SIZE = 28;
|
||||
|
||||
export const LeftActions = React.memo(({ theme, transX, isRead, width, onToggleReadPress, displayMode }: ILeftActions) => {
|
||||
export const LeftActions = React.memo(({ theme, transX, isRead, width, onToggleReadPress, displayMode }: ILeftActionsProps) => {
|
||||
const translateX = Animated.multiply(
|
||||
transX.interpolate({
|
||||
inputRange: [0, ACTION_WIDTH],
|
||||
|
@ -44,7 +25,7 @@ export const LeftActions = React.memo(({ theme, transX, isRead, width, onToggleR
|
|||
const viewHeight = isCondensed ? { height: ROW_HEIGHT_CONDENSED } : null;
|
||||
|
||||
return (
|
||||
<View style={[styles.actionsContainer, styles.actionLeftContainer]} pointerEvents='box-none'>
|
||||
<View style={[styles.actionsContainer, styles.actionsLeftContainer]} pointerEvents='box-none'>
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.actionLeftButtonContainer,
|
||||
|
@ -71,7 +52,7 @@ export const LeftActions = React.memo(({ theme, transX, isRead, width, onToggleR
|
|||
});
|
||||
|
||||
export const RightActions = React.memo(
|
||||
({ transX, favorite, width, toggleFav, onHidePress, theme, displayMode }: IRightActions) => {
|
||||
({ transX, favorite, width, toggleFav, onHidePress, theme, displayMode }: IRightActionsProps) => {
|
||||
const translateXFav = Animated.multiply(
|
||||
transX.interpolate({
|
||||
inputRange: [-width / 2, -ACTION_WIDTH * 2, 0],
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import { View } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Avatar from '../../containers/Avatar';
|
||||
import Avatar from '../Avatar';
|
||||
import { DisplayMode } from '../../lib/constants';
|
||||
import TypeIcon from './TypeIcon';
|
||||
import styles from './styles';
|
|
@ -3,28 +3,11 @@ import { dequal } from 'dequal';
|
|||
|
||||
import I18n from '../../i18n';
|
||||
import styles from './styles';
|
||||
import { MarkdownPreview } from '../../containers/markdown';
|
||||
import { MarkdownPreview } from '../markdown';
|
||||
import { E2E_MESSAGE_TYPE, E2E_STATUS, themes } from '../../lib/constants';
|
||||
import { TSupportedThemes } from '../../theme';
|
||||
import { ILastMessageProps } from './interfaces';
|
||||
|
||||
interface ILastMessage {
|
||||
theme: TSupportedThemes;
|
||||
lastMessage: {
|
||||
u: any;
|
||||
pinned: boolean;
|
||||
t: string;
|
||||
attachments: any;
|
||||
msg: string;
|
||||
e2e: string;
|
||||
};
|
||||
type: string;
|
||||
showLastMessage: boolean;
|
||||
username: string;
|
||||
useRealName: boolean;
|
||||
alert: boolean;
|
||||
}
|
||||
|
||||
const formatMsg = ({ lastMessage, type, showLastMessage, username, useRealName }: Partial<ILastMessage>) => {
|
||||
const formatMsg = ({ lastMessage, type, showLastMessage, username, useRealName }: Partial<ILastMessageProps>) => {
|
||||
if (!showLastMessage) {
|
||||
return '';
|
||||
}
|
||||
|
@ -64,7 +47,7 @@ const formatMsg = ({ lastMessage, type, showLastMessage, username, useRealName }
|
|||
const arePropsEqual = (oldProps: any, newProps: any) => dequal(oldProps, newProps);
|
||||
|
||||
const LastMessage = React.memo(
|
||||
({ lastMessage, type, showLastMessage, username, alert, useRealName, theme }: ILastMessage) => (
|
||||
({ lastMessage, type, showLastMessage, username, alert, useRealName, theme }: ILastMessageProps) => (
|
||||
<MarkdownPreview
|
||||
msg={formatMsg({
|
||||
lastMessage,
|
|
@ -3,7 +3,7 @@ import { View } from 'react-native';
|
|||
|
||||
import styles from './styles';
|
||||
import Wrapper from './Wrapper';
|
||||
import UnreadBadge from '../../containers/UnreadBadge';
|
||||
import UnreadBadge from '../UnreadBadge';
|
||||
import TypeIcon from './TypeIcon';
|
||||
import LastMessage from './LastMessage';
|
||||
import Title from './Title';
|
||||
|
@ -12,58 +12,7 @@ import Touchable from './Touchable';
|
|||
import Tag from './Tag';
|
||||
import I18n from '../../i18n';
|
||||
import { DisplayMode } from '../../lib/constants';
|
||||
import { TUserStatus, IOmnichannelSource } from '../../definitions';
|
||||
import { TSupportedThemes } from '../../theme';
|
||||
|
||||
interface IRoomItem {
|
||||
rid: string;
|
||||
type: string;
|
||||
prid: string;
|
||||
name: string;
|
||||
avatar: string;
|
||||
showLastMessage: boolean;
|
||||
username: string;
|
||||
avatarSize: number;
|
||||
testID: string;
|
||||
width: number;
|
||||
status: TUserStatus;
|
||||
useRealName: boolean;
|
||||
theme: TSupportedThemes;
|
||||
isFocused: boolean;
|
||||
isGroupChat: boolean;
|
||||
isRead: boolean;
|
||||
teamMain: boolean;
|
||||
date: string;
|
||||
accessibilityLabel: string;
|
||||
lastMessage: {
|
||||
u: any;
|
||||
pinned: boolean;
|
||||
t: string;
|
||||
attachments: any;
|
||||
msg: string;
|
||||
e2e: string;
|
||||
};
|
||||
favorite: boolean;
|
||||
alert: boolean;
|
||||
hideUnreadStatus: boolean;
|
||||
unread: number;
|
||||
userMentions: number;
|
||||
groupMentions: number;
|
||||
tunread: [];
|
||||
tunreadUser: [];
|
||||
tunreadGroup: [];
|
||||
swipeEnabled: boolean;
|
||||
toggleFav(): void;
|
||||
toggleRead(): void;
|
||||
onPress(): void;
|
||||
onLongPress(): void;
|
||||
hideChannel(): void;
|
||||
autoJoin: boolean;
|
||||
size?: number;
|
||||
showAvatar: boolean;
|
||||
displayMode: string;
|
||||
sourceType: IOmnichannelSource;
|
||||
}
|
||||
import { IRoomItemProps } from './interfaces';
|
||||
|
||||
const RoomItem = ({
|
||||
rid,
|
||||
|
@ -72,7 +21,6 @@ const RoomItem = ({
|
|||
name,
|
||||
avatar,
|
||||
width,
|
||||
avatarSize = 48,
|
||||
username,
|
||||
showLastMessage,
|
||||
status = 'offline',
|
||||
|
@ -105,7 +53,7 @@ const RoomItem = ({
|
|||
showAvatar,
|
||||
displayMode,
|
||||
sourceType
|
||||
}: IRoomItem) => (
|
||||
}: IRoomItemProps) => (
|
||||
<Touchable
|
||||
onPress={onPress}
|
||||
onLongPress={onLongPress}
|
||||
|
@ -125,7 +73,6 @@ const RoomItem = ({
|
|||
<Wrapper
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
avatar={avatar}
|
||||
avatarSize={avatarSize}
|
||||
type={type}
|
||||
theme={theme}
|
||||
rid={rid}
|
|
@ -3,16 +3,9 @@ import { Text } from 'react-native';
|
|||
|
||||
import styles from './styles';
|
||||
import { themes } from '../../lib/constants';
|
||||
import { TSupportedThemes } from '../../theme';
|
||||
import { ITitleProps } from './interfaces';
|
||||
|
||||
interface ITitle {
|
||||
name: string;
|
||||
theme: TSupportedThemes;
|
||||
hideUnreadStatus: boolean;
|
||||
alert: boolean;
|
||||
}
|
||||
|
||||
const Title = React.memo(({ name, theme, hideUnreadStatus, alert }: ITitle) => (
|
||||
const Title = React.memo(({ name, theme, hideUnreadStatus, alert }: ITitleProps) => (
|
||||
<Text
|
||||
style={[styles.title, alert && !hideUnreadStatus && styles.alert, { color: themes[theme].titleText }]}
|
||||
ellipsizeMode='tail'
|
|
@ -1,46 +1,28 @@
|
|||
import React from 'react';
|
||||
import { Animated } from 'react-native';
|
||||
import { LongPressGestureHandler, PanGestureHandler, State } from 'react-native-gesture-handler';
|
||||
import {
|
||||
GestureEvent,
|
||||
HandlerStateChangeEventPayload,
|
||||
LongPressGestureHandler,
|
||||
PanGestureHandler,
|
||||
PanGestureHandlerEventPayload,
|
||||
State
|
||||
} from 'react-native-gesture-handler';
|
||||
|
||||
import Touch from '../../utils/touch';
|
||||
import { ACTION_WIDTH, LONG_SWIPE, SMALL_SWIPE } from './styles';
|
||||
import { isRTL } from '../../i18n';
|
||||
import { themes } from '../../lib/constants';
|
||||
import { LeftActions, RightActions } from './Actions';
|
||||
import { TSupportedThemes } from '../../theme';
|
||||
|
||||
interface ITouchableProps {
|
||||
children: JSX.Element;
|
||||
type: string;
|
||||
onPress(): void;
|
||||
onLongPress(): void;
|
||||
testID: string;
|
||||
width: number;
|
||||
favorite: boolean;
|
||||
isRead: boolean;
|
||||
rid: string;
|
||||
toggleFav: Function;
|
||||
toggleRead: Function;
|
||||
hideChannel: Function;
|
||||
theme: TSupportedThemes;
|
||||
isFocused: boolean;
|
||||
swipeEnabled: boolean;
|
||||
displayMode: string;
|
||||
}
|
||||
import { ITouchableProps } from './interfaces';
|
||||
|
||||
class Touchable extends React.Component<ITouchableProps, any> {
|
||||
private dragX: Animated.Value;
|
||||
|
||||
private rowOffSet: Animated.Value;
|
||||
|
||||
private reverse: Animated.Value;
|
||||
|
||||
private transX: Animated.AnimatedAddition;
|
||||
|
||||
private transXReverse: Animated.AnimatedMultiplication;
|
||||
|
||||
private _onGestureEvent: (...args: any[]) => void;
|
||||
|
||||
private _onGestureEvent: (event: GestureEvent<PanGestureHandlerEventPayload>) => void;
|
||||
private _value: number;
|
||||
|
||||
constructor(props: ITouchableProps) {
|
||||
|
@ -57,19 +39,19 @@ class Touchable extends React.Component<ITouchableProps, any> {
|
|||
this._value = 0;
|
||||
}
|
||||
|
||||
_onHandlerStateChange = ({ nativeEvent }: any) => {
|
||||
_onHandlerStateChange = ({ nativeEvent }: { nativeEvent: HandlerStateChangeEventPayload & PanGestureHandlerEventPayload }) => {
|
||||
if (nativeEvent.oldState === State.ACTIVE) {
|
||||
this._handleRelease(nativeEvent);
|
||||
}
|
||||
};
|
||||
|
||||
onLongPressHandlerStateChange = ({ nativeEvent }: any) => {
|
||||
onLongPressHandlerStateChange = ({ nativeEvent }: { nativeEvent: HandlerStateChangeEventPayload }) => {
|
||||
if (nativeEvent.state === State.ACTIVE) {
|
||||
this.onLongPress();
|
||||
}
|
||||
};
|
||||
|
||||
_handleRelease = (nativeEvent: any) => {
|
||||
_handleRelease = (nativeEvent: PanGestureHandlerEventPayload) => {
|
||||
const { translationX } = nativeEvent;
|
||||
const { rowState } = this.state;
|
||||
this._value += translationX;
|
||||
|
@ -155,7 +137,7 @@ class Touchable extends React.Component<ITouchableProps, any> {
|
|||
this._animateRow(toValue);
|
||||
};
|
||||
|
||||
_animateRow = (toValue: any) => {
|
||||
_animateRow = (toValue: number) => {
|
||||
this.rowOffSet.setValue(this._value);
|
||||
this._value = toValue;
|
||||
this.dragX.setValue(0);
|
|
@ -0,0 +1,17 @@
|
|||
import React from 'react';
|
||||
|
||||
import RoomTypeIcon from '../RoomTypeIcon';
|
||||
import { ITypeIconProps } from './interfaces';
|
||||
|
||||
const TypeIcon = React.memo(({ type, prid, status, isGroupChat, teamMain, size, style }: ITypeIconProps) => (
|
||||
<RoomTypeIcon
|
||||
type={prid ? 'discussion' : type}
|
||||
isGroupChat={isGroupChat}
|
||||
status={status}
|
||||
teamMain={teamMain}
|
||||
size={size}
|
||||
style={style}
|
||||
/>
|
||||
));
|
||||
|
||||
export default TypeIcon;
|
|
@ -4,16 +4,9 @@ import { Text } from 'react-native';
|
|||
import styles from './styles';
|
||||
import { themes } from '../../lib/constants';
|
||||
import { capitalize } from '../../utils/room';
|
||||
import { TSupportedThemes } from '../../theme';
|
||||
import { IUpdatedAtProps } from './interfaces';
|
||||
|
||||
interface IUpdatedAt {
|
||||
date: string;
|
||||
theme: TSupportedThemes;
|
||||
hideUnreadStatus: boolean;
|
||||
alert: boolean;
|
||||
}
|
||||
|
||||
const UpdatedAt = React.memo(({ date, theme, hideUnreadStatus, alert }: IUpdatedAt) => {
|
||||
const UpdatedAt = React.memo(({ date, theme, hideUnreadStatus, alert }: IUpdatedAtProps) => {
|
||||
if (!date) {
|
||||
return null;
|
||||
}
|
|
@ -2,30 +2,11 @@ import React from 'react';
|
|||
import { View } from 'react-native';
|
||||
|
||||
import { DisplayMode, themes } from '../../lib/constants';
|
||||
import { IOmnichannelSource } from '../../definitions';
|
||||
import { TSupportedThemes } from '../../theme';
|
||||
import IconOrAvatar from './IconOrAvatar';
|
||||
import { IWrapperProps } from './interfaces';
|
||||
import styles from './styles';
|
||||
|
||||
interface IWrapper {
|
||||
accessibilityLabel: string;
|
||||
avatar: string;
|
||||
avatarSize: number;
|
||||
type: string;
|
||||
theme: TSupportedThemes;
|
||||
rid: string;
|
||||
children: JSX.Element;
|
||||
displayMode: string;
|
||||
prid: string;
|
||||
showLastMessage: boolean;
|
||||
status: string;
|
||||
isGroupChat: boolean;
|
||||
teamMain: boolean;
|
||||
showAvatar: boolean;
|
||||
sourceType: IOmnichannelSource;
|
||||
}
|
||||
|
||||
const Wrapper = ({ accessibilityLabel, theme, children, displayMode, ...props }: IWrapper) => (
|
||||
const Wrapper = ({ accessibilityLabel, theme, children, displayMode, ...props }: IWrapperProps): React.ReactElement => (
|
||||
<View
|
||||
style={[styles.container, displayMode === DisplayMode.Condensed && styles.containerCondensed]}
|
||||
accessibilityLabel={accessibilityLabel}>
|
|
@ -5,37 +5,10 @@ import I18n from '../../i18n';
|
|||
import { ROW_HEIGHT, ROW_HEIGHT_CONDENSED } from './styles';
|
||||
import { formatDate } from '../../utils/room';
|
||||
import RoomItem from './RoomItem';
|
||||
import { TUserStatus } from '../../definitions';
|
||||
import { TSupportedThemes } from '../../theme';
|
||||
import { ISubscription, TUserStatus } from '../../definitions';
|
||||
import { IRoomItemContainerProps } from './interfaces';
|
||||
|
||||
export { ROW_HEIGHT, ROW_HEIGHT_CONDENSED };
|
||||
interface IRoomItemContainerProps {
|
||||
item: any;
|
||||
showLastMessage: boolean;
|
||||
id: string;
|
||||
onPress: Function;
|
||||
onLongPress: Function;
|
||||
username: string;
|
||||
avatarSize: number;
|
||||
width: number;
|
||||
status: TUserStatus;
|
||||
toggleFav(): void;
|
||||
toggleRead(): void;
|
||||
hideChannel(): void;
|
||||
useRealName: boolean;
|
||||
getUserPresence: Function;
|
||||
connected: boolean;
|
||||
theme: TSupportedThemes;
|
||||
isFocused: boolean;
|
||||
getRoomTitle: Function;
|
||||
getRoomAvatar: Function;
|
||||
getIsGroupChat: Function;
|
||||
getIsRead: Function;
|
||||
swipeEnabled: boolean;
|
||||
autoJoin: boolean;
|
||||
showAvatar: boolean;
|
||||
displayMode: string;
|
||||
}
|
||||
|
||||
const attrs = [
|
||||
'width',
|
||||
|
@ -51,12 +24,9 @@ const attrs = [
|
|||
];
|
||||
|
||||
class RoomItemContainer extends React.Component<IRoomItemContainerProps, any> {
|
||||
private mounted: boolean;
|
||||
|
||||
private roomSubscription: any;
|
||||
private roomSubscription: ISubscription | undefined;
|
||||
|
||||
static defaultProps: Partial<IRoomItemContainerProps> = {
|
||||
avatarSize: 48,
|
||||
status: 'offline',
|
||||
getUserPresence: () => {},
|
||||
getRoomTitle: () => 'title',
|
||||
|
@ -68,24 +38,22 @@ class RoomItemContainer extends React.Component<IRoomItemContainerProps, any> {
|
|||
|
||||
constructor(props: IRoomItemContainerProps) {
|
||||
super(props);
|
||||
this.mounted = false;
|
||||
this.init();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.mounted = true;
|
||||
const { connected, getUserPresence, id } = this.props;
|
||||
if (connected && this.isDirect) {
|
||||
getUserPresence(id);
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps: any) {
|
||||
const { props }: any = this;
|
||||
shouldComponentUpdate(nextProps: IRoomItemContainerProps) {
|
||||
const { props } = this;
|
||||
return !attrs.every(key => props[key] === nextProps[key]);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: any) {
|
||||
componentDidUpdate(prevProps: IRoomItemContainerProps) {
|
||||
const { connected, getUserPresence, id } = this.props;
|
||||
if (prevProps.connected !== connected && connected && this.isDirect) {
|
||||
getUserPresence(id);
|
||||
|
@ -107,7 +75,7 @@ class RoomItemContainer extends React.Component<IRoomItemContainerProps, any> {
|
|||
const {
|
||||
item: { t },
|
||||
id
|
||||
}: any = this.props;
|
||||
} = this.props;
|
||||
return t === 'd' && id && !this.isGroupChat;
|
||||
}
|
||||
|
||||
|
@ -145,7 +113,6 @@ class RoomItemContainer extends React.Component<IRoomItemContainerProps, any> {
|
|||
hideChannel,
|
||||
theme,
|
||||
isFocused,
|
||||
avatarSize,
|
||||
status,
|
||||
showLastMessage,
|
||||
username,
|
||||
|
@ -178,7 +145,6 @@ class RoomItemContainer extends React.Component<IRoomItemContainerProps, any> {
|
|||
}
|
||||
|
||||
return (
|
||||
// @ts-ignore
|
||||
<RoomItem
|
||||
name={name}
|
||||
avatar={avatar}
|
||||
|
@ -198,7 +164,6 @@ class RoomItemContainer extends React.Component<IRoomItemContainerProps, any> {
|
|||
type={item.t}
|
||||
theme={theme}
|
||||
isFocused={isFocused}
|
||||
size={avatarSize}
|
||||
prid={item.prid}
|
||||
status={status}
|
||||
hideUnreadStatus={item.hideUnreadStatus}
|
|
@ -0,0 +1,166 @@
|
|||
import React from 'react';
|
||||
import { Animated } from 'react-native';
|
||||
|
||||
import { TSupportedThemes } from '../../theme';
|
||||
import { TUserStatus, ILastMessage, SubscriptionType, IOmnichannelSource } from '../../definitions';
|
||||
|
||||
export interface ILeftActionsProps {
|
||||
theme: TSupportedThemes;
|
||||
transX: Animated.AnimatedAddition | Animated.AnimatedMultiplication;
|
||||
isRead: boolean;
|
||||
width: number;
|
||||
onToggleReadPress(): void;
|
||||
displayMode: string;
|
||||
}
|
||||
|
||||
export interface IRightActionsProps {
|
||||
theme: TSupportedThemes;
|
||||
transX: Animated.AnimatedAddition | Animated.AnimatedMultiplication;
|
||||
favorite: boolean;
|
||||
width: number;
|
||||
toggleFav(): void;
|
||||
onHidePress(): void;
|
||||
displayMode: string;
|
||||
}
|
||||
|
||||
export interface ITitleProps {
|
||||
name: string;
|
||||
theme: TSupportedThemes;
|
||||
hideUnreadStatus: boolean;
|
||||
alert: boolean;
|
||||
}
|
||||
|
||||
export interface IUpdatedAtProps {
|
||||
date: string;
|
||||
theme: TSupportedThemes;
|
||||
hideUnreadStatus: boolean;
|
||||
alert: boolean;
|
||||
}
|
||||
|
||||
export interface IWrapperProps {
|
||||
accessibilityLabel: string;
|
||||
avatar: string;
|
||||
type: string;
|
||||
theme: TSupportedThemes;
|
||||
rid: string;
|
||||
children: React.ReactElement;
|
||||
displayMode: string;
|
||||
prid: string;
|
||||
showLastMessage: boolean;
|
||||
status: string;
|
||||
isGroupChat: boolean;
|
||||
teamMain: boolean;
|
||||
showAvatar: boolean;
|
||||
sourceType: IOmnichannelSource;
|
||||
}
|
||||
|
||||
export interface ITypeIconProps {
|
||||
type: string;
|
||||
status: TUserStatus;
|
||||
prid: string;
|
||||
isGroupChat: boolean;
|
||||
teamMain: boolean;
|
||||
theme?: TSupportedThemes;
|
||||
size?: number;
|
||||
style?: object;
|
||||
sourceType: IOmnichannelSource;
|
||||
}
|
||||
|
||||
export interface IRoomItemContainerProps {
|
||||
[key: string]: string | boolean | Function | number;
|
||||
item: any;
|
||||
showLastMessage: boolean;
|
||||
id: string;
|
||||
onPress: (item: any) => void;
|
||||
onLongPress: (item: any) => Promise<void>;
|
||||
username: string;
|
||||
width: number;
|
||||
status: TUserStatus;
|
||||
toggleFav(): void;
|
||||
toggleRead(): void;
|
||||
hideChannel(): void;
|
||||
useRealName: boolean;
|
||||
getUserPresence: (uid: string) => void;
|
||||
connected: boolean;
|
||||
theme: TSupportedThemes;
|
||||
isFocused: boolean;
|
||||
getRoomTitle: (item: any) => string;
|
||||
getRoomAvatar: (item: any) => string;
|
||||
getIsGroupChat: (item: any) => boolean;
|
||||
getIsRead: (item: any) => boolean;
|
||||
swipeEnabled: boolean;
|
||||
autoJoin: boolean;
|
||||
showAvatar: boolean;
|
||||
displayMode: string;
|
||||
}
|
||||
|
||||
export interface IRoomItemProps {
|
||||
rid: string;
|
||||
type: SubscriptionType;
|
||||
prid: string;
|
||||
name: string;
|
||||
avatar: string;
|
||||
showLastMessage: boolean;
|
||||
username: string;
|
||||
testID: string;
|
||||
width: number;
|
||||
status: TUserStatus;
|
||||
useRealName: boolean;
|
||||
theme: TSupportedThemes;
|
||||
isFocused: boolean;
|
||||
isGroupChat: boolean;
|
||||
isRead: boolean;
|
||||
teamMain: boolean;
|
||||
date: string;
|
||||
accessibilityLabel: string;
|
||||
lastMessage: ILastMessage;
|
||||
favorite: boolean;
|
||||
alert: boolean;
|
||||
hideUnreadStatus: boolean;
|
||||
unread: number;
|
||||
userMentions: number;
|
||||
groupMentions: number;
|
||||
tunread: [];
|
||||
tunreadUser: [];
|
||||
tunreadGroup: [];
|
||||
swipeEnabled: boolean;
|
||||
toggleFav(): void;
|
||||
toggleRead(): void;
|
||||
onPress(): void;
|
||||
onLongPress(): void;
|
||||
hideChannel(): void;
|
||||
autoJoin: boolean;
|
||||
size?: number;
|
||||
showAvatar: boolean;
|
||||
displayMode: string;
|
||||
sourceType: IOmnichannelSource;
|
||||
}
|
||||
|
||||
export interface ILastMessageProps {
|
||||
theme: TSupportedThemes;
|
||||
lastMessage: ILastMessage;
|
||||
type: SubscriptionType;
|
||||
showLastMessage: boolean;
|
||||
username: string;
|
||||
useRealName: boolean;
|
||||
alert: boolean;
|
||||
}
|
||||
|
||||
export interface ITouchableProps {
|
||||
children: JSX.Element;
|
||||
type: string;
|
||||
onPress(): void;
|
||||
onLongPress(): void;
|
||||
testID: string;
|
||||
width: number;
|
||||
favorite: boolean;
|
||||
isRead: boolean;
|
||||
rid: string;
|
||||
toggleFav: Function;
|
||||
toggleRead: Function;
|
||||
hideChannel: Function;
|
||||
theme: TSupportedThemes;
|
||||
isFocused: boolean;
|
||||
swipeEnabled: boolean;
|
||||
displayMode: string;
|
||||
}
|
|
@ -8,7 +8,7 @@ export const ACTION_WIDTH = 80;
|
|||
export const SMALL_SWIPE = ACTION_WIDTH / 2;
|
||||
export const LONG_SWIPE = ACTION_WIDTH * 3;
|
||||
|
||||
export default StyleSheet.create<any>({
|
||||
export default StyleSheet.create({
|
||||
flex: {
|
||||
flex: 1
|
||||
},
|
|
@ -354,7 +354,8 @@ class MessageContainer extends React.Component<IMessageContainerProps, IMessageC
|
|||
blocks,
|
||||
autoTranslate: autoTranslateMessage,
|
||||
replies,
|
||||
md
|
||||
md,
|
||||
comment
|
||||
} = item;
|
||||
|
||||
let message = msg;
|
||||
|
@ -435,6 +436,7 @@ class MessageContainer extends React.Component<IMessageContainerProps, IMessageC
|
|||
callJitsi={callJitsi}
|
||||
blockAction={blockAction}
|
||||
highlighted={highlighted}
|
||||
comment={comment}
|
||||
/>
|
||||
</MessageContext.Provider>
|
||||
);
|
||||
|
|
|
@ -59,6 +59,7 @@ export interface IMessageContent {
|
|||
useRealName?: boolean;
|
||||
isIgnored: boolean;
|
||||
type: string;
|
||||
comment?: string;
|
||||
}
|
||||
|
||||
export interface IMessageEmoji {
|
||||
|
|
|
@ -55,7 +55,9 @@ export const SYSTEM_MESSAGES = [
|
|||
'user-converted-to-team',
|
||||
'user-converted-to-channel',
|
||||
'user-deleted-room-from-team',
|
||||
'user-removed-room-from-team'
|
||||
'user-removed-room-from-team',
|
||||
'omnichannel_placed_chat_on_hold',
|
||||
'omnichannel_on_hold_chat_resumed'
|
||||
];
|
||||
|
||||
export const SYSTEM_MESSAGE_TYPES = {
|
||||
|
@ -73,7 +75,9 @@ export const SYSTEM_MESSAGE_TYPES = {
|
|||
CONVERTED_TO_TEAM: 'user-converted-to-team',
|
||||
CONVERTED_TO_CHANNEL: 'user-converted-to-channel',
|
||||
DELETED_ROOM_FROM_TEAM: 'user-deleted-room-from-team',
|
||||
REMOVED_ROOM_FROM_TEAM: 'user-removed-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'
|
||||
};
|
||||
|
||||
export const SYSTEM_MESSAGE_TYPES_WITH_AUTHOR_NAME = [
|
||||
|
@ -99,9 +103,10 @@ type TInfoMessage = {
|
|||
role: string;
|
||||
msg: string;
|
||||
author: { username: string };
|
||||
comment?: string;
|
||||
};
|
||||
|
||||
export const getInfoMessage = ({ type, role, msg, author }: TInfoMessage): string => {
|
||||
export const getInfoMessage = ({ type, role, msg, author, comment }: TInfoMessage): string => {
|
||||
const { username } = author;
|
||||
if (type === 'rm') {
|
||||
return I18n.t('Message_removed');
|
||||
|
@ -193,6 +198,12 @@ export const getInfoMessage = ({ type, role, msg, author }: TInfoMessage): strin
|
|||
if (type === 'user-removed-room-from-team') {
|
||||
return I18n.t('Removed__roomName__from_this_team', { roomName: msg });
|
||||
}
|
||||
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 '';
|
||||
};
|
||||
|
||||
|
|
|
@ -42,16 +42,16 @@ export interface ITranslations {
|
|||
export type E2EType = 'pending' | 'done';
|
||||
|
||||
export interface ILastMessage {
|
||||
_id: string;
|
||||
rid: string;
|
||||
_id?: string;
|
||||
rid?: string;
|
||||
tshow?: boolean;
|
||||
t?: MessageType;
|
||||
tmid?: string;
|
||||
msg?: string;
|
||||
e2e?: E2EType;
|
||||
ts: string | Date;
|
||||
ts?: string | Date;
|
||||
u: IUserMessage;
|
||||
_updatedAt: string | Date;
|
||||
_updatedAt?: string | Date;
|
||||
urls?: IUrlFromServer[];
|
||||
mentions?: IUserMention[];
|
||||
channels?: IUserChannel[];
|
||||
|
@ -59,7 +59,9 @@ export interface ILastMessage {
|
|||
attachments?: IAttachment[];
|
||||
reactions?: IReaction[];
|
||||
unread?: boolean;
|
||||
pinned?: boolean;
|
||||
status?: number;
|
||||
token?: string;
|
||||
}
|
||||
|
||||
interface IMessageFile {
|
||||
|
@ -140,6 +142,7 @@ export interface IMessage extends IMessageFromServer {
|
|||
blocks?: any;
|
||||
e2e?: E2EType;
|
||||
tshow?: boolean;
|
||||
comment?: string;
|
||||
subscription?: { id: string };
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,8 @@ export interface IRoom {
|
|||
uids: Array<string>;
|
||||
lm?: Date;
|
||||
sysMes?: string[];
|
||||
onHold?: boolean;
|
||||
waitingResponse?: boolean;
|
||||
}
|
||||
|
||||
export enum OmnichannelSourceType {
|
||||
|
|
|
@ -98,6 +98,7 @@ export interface ISubscription {
|
|||
teamMain?: boolean;
|
||||
unsubscribe: () => Promise<any>;
|
||||
separator?: boolean;
|
||||
onHold?: boolean;
|
||||
source?: IOmnichannelSource;
|
||||
// https://nozbe.github.io/WatermelonDB/Relation.html#relation-api
|
||||
messages: RelationModified<TMessageModel>;
|
||||
|
|
|
@ -17,6 +17,9 @@ export const getInquiriesQueued = () => sdk.get('livechat/inquiries.queued');
|
|||
// RC 2.4.0
|
||||
export const takeInquiry = (inquiryId: string) => sdk.methodCallWrapper('livechat:takeInquiry', inquiryId);
|
||||
|
||||
// RC 4.26
|
||||
export const takeResume = (roomId: string) => sdk.methodCallWrapper('livechat:resumeOnHold', roomId);
|
||||
|
||||
class Omnichannel {
|
||||
private inquirySub: { stop: () => void } | null;
|
||||
constructor() {
|
||||
|
|
|
@ -6,7 +6,7 @@ import { connect } from 'react-redux';
|
|||
import { dequal } from 'dequal';
|
||||
|
||||
import I18n from '../../../i18n';
|
||||
import RoomItem, { ROW_HEIGHT } from '../../../presentation/RoomItem';
|
||||
import RoomItem, { ROW_HEIGHT } from '../../../containers/RoomItem';
|
||||
import { isIOS, isTablet } from '../../../utils/deviceInfo';
|
||||
import { getUserSelector } from '../../../selectors/login';
|
||||
import { TSupportedThemes, withTheme } from '../../../theme';
|
||||
|
|
|
@ -358,7 +358,6 @@
|
|||
"Offline": "غير متصل",
|
||||
"Oops": "عفوًا!",
|
||||
"Omnichannel": "القنوات الموحدة",
|
||||
"Open_Livechats": "محادثات مباشرة جارية",
|
||||
"Omnichannel_enable_alert": "أنت غير متاح ",
|
||||
"Onboarding_description": "مساحة عمل هي مساحة لفريقك ومنظمتك للتعاون. اطلب من المشرف العنوان للانضمام أو أنشئ لفريقك",
|
||||
"Onboarding_join_workspace": "انضم لمساحة عمل",
|
||||
|
|
|
@ -363,7 +363,6 @@
|
|||
"Offline": "Offline",
|
||||
"Oops": "Hoppla!",
|
||||
"Omnichannel": "Omnichannel",
|
||||
"Open_Livechats": "Offene Chats",
|
||||
"Omnichannel_enable_alert": "Sie sind in Omnichannel nicht verfügbar. Möchten Sie erreichbar sein?",
|
||||
"Onboarding_description": "Ein Arbeitsbereich ist der Ort für die Zusammenarbeit deines Teams oder Organisation. Bitten Sie den Admin des Arbeitsbereichs um eine Adresse, um ihm beizutreten, oder erstellen Sie einen Arbeitsbereich für Ihr Team.",
|
||||
"Onboarding_join_workspace": "Einem Arbeitsbereich beiteten",
|
||||
|
|
|
@ -363,7 +363,6 @@
|
|||
"Offline": "Offline",
|
||||
"Oops": "Oops!",
|
||||
"Omnichannel": "Omnichannel",
|
||||
"Open_Livechats": "Chats in Progress",
|
||||
"Omnichannel_enable_alert": "You're not available on Omnichannel. Would you like to be available?",
|
||||
"Onboarding_description": "A workspace is your team or organization’s space to collaborate. Ask the workspace admin for address to join or create one for your team.",
|
||||
"Onboarding_join_workspace": "Join a workspace",
|
||||
|
@ -808,6 +807,14 @@
|
|||
"Removed__username__from_team": "removed @{{user_removed}} from this Team",
|
||||
"User_joined_team": "joined this Team",
|
||||
"User_left_team": "left this Team",
|
||||
"Place_chat_on_hold": "Place chat on-hold",
|
||||
"Would_like_to_place_on_hold": "Would you like to place this chat On-Hold?",
|
||||
"Open_Livechats": "Omnichannel chats in progress",
|
||||
"On_hold_Livechats": "Omnichannel chats on hold",
|
||||
"Chat_is_on_hold": "This chat is on-hold due to inactivity",
|
||||
"Resume": "Resume",
|
||||
"Omnichannel_placed_chat_on_hold": "Chat On Hold: {{comment}}",
|
||||
"Omnichannel_on_hold_chat_resumed": "On Hold Chat Resumed: {{comment}}",
|
||||
"Omnichannel_queue": "Omnichannel queue",
|
||||
"Empty": "Empty"
|
||||
}
|
|
@ -363,7 +363,6 @@
|
|||
"Offline": "Hors ligne",
|
||||
"Oops": "Oups !",
|
||||
"Omnichannel": "Omnicanal",
|
||||
"Open_Livechats": "Discussions en cours",
|
||||
"Omnichannel_enable_alert": "Vous n'êtes pas disponible sur Omnicanal. Souhaitez-vous être disponible ?",
|
||||
"Onboarding_description": "Un espace de travail est l'espace de collaboration de votre équipe ou organisation. Demandez à l'administrateur de l'espace de travail l'adresse pour rejoindre ou créez-en une pour votre équipe.",
|
||||
"Onboarding_join_workspace": "Rejoindre un espace de travail",
|
||||
|
|
|
@ -352,7 +352,6 @@
|
|||
"Offline": "Offline",
|
||||
"Oops": "Oops!",
|
||||
"Omnichannel": "Omnichannel",
|
||||
"Open_Livechats": "Chat in corso",
|
||||
"Omnichannel_enable_alert": "Non sei ancora su Onmichannel. Vuoi attivarlo?",
|
||||
"Onboarding_description": "Un workspace è lo spazio dove il tuo team o la tua organizzazione possono collaborare. Chiedi l'indirizzo all'amministratore del tuo workspace oppure creane uno per il tuo team.",
|
||||
"Onboarding_join_workspace": "Unisciti",
|
||||
|
|
|
@ -363,7 +363,6 @@
|
|||
"Offline": "Offline",
|
||||
"Oops": "Oeps!",
|
||||
"Omnichannel": "Omnichannel",
|
||||
"Open_Livechats": "Bezig met chatten",
|
||||
"Omnichannel_enable_alert": "Je bent niet beschikbaar op Omnichannel. Wil je beschikbaar zijn?",
|
||||
"Onboarding_description": "Een werkruimte is de ruimte van jouw team of organisatie om samen te werken. Vraag aan de beheerder van de werkruimte een adres om lid te worden of maak er een aan voor jouw team.",
|
||||
"Onboarding_join_workspace": "Word lid van een werkruimte",
|
||||
|
|
|
@ -339,7 +339,6 @@
|
|||
"Offline": "Offline",
|
||||
"Oops": "Ops!",
|
||||
"Omnichannel": "Omnichannel",
|
||||
"Open_Livechats": "Bate-papos em Andamento",
|
||||
"Omnichannel_enable_alert": "Você não está disponível no Omnichannel. Você quer ficar disponível?",
|
||||
"Onboarding_description": "Workspace é o espaço de colaboração do seu time ou organização. Peça um convite ou o endereço ao seu administrador ou crie uma workspace para o seu time.",
|
||||
"Onboarding_join_workspace": "Entre numa workspace",
|
||||
|
|
|
@ -359,7 +359,6 @@
|
|||
"Offline": "Desligado",
|
||||
"Oops": "Oops!",
|
||||
"Omnichannel": "Omnichannel",
|
||||
"Open_Livechats": "Chats em andamento",
|
||||
"Omnichannel_enable_alert": "Você não está disponível no Omnichannel. Você gostaria de estar disponível?",
|
||||
"Onboarding_description": "Um espaço de trabalho é o espaço da sua equipa ou organização para colaborar. Peça ao administrador do espaço de trabalho um endereço para se juntar ou criar um para a sua equipa.",
|
||||
"Onboarding_join_workspace": "Junte-se a um espaço de trabalho",
|
||||
|
|
|
@ -363,7 +363,6 @@
|
|||
"Offline": "Офлайн",
|
||||
"Oops": "Упс!",
|
||||
"Omnichannel": "Omnichannel",
|
||||
"Open_Livechats": "Чаты в Работе",
|
||||
"Omnichannel_enable_alert": "Вы не доступны в Omnichannel. Хотите стать доступными?",
|
||||
"Onboarding_description": "Сервер это пространство для взаимодействия вашей команды или организации. Уточните адрес сервера у вашего администратора или создайте свой сервер для команды.",
|
||||
"Onboarding_join_workspace": "Присоединиться к серверу",
|
||||
|
|
|
@ -353,7 +353,6 @@
|
|||
"Offline": "Çevrimdışı",
|
||||
"Oops": "Ahh!",
|
||||
"Omnichannel": "Çoklu Kanal",
|
||||
"Open_Livechats": "Devam Eden Sohbetler",
|
||||
"Omnichannel_enable_alert": "Çoklu Kanal'da mevcut değilsiniz. Erişilebilir olmak ister misiniz?",
|
||||
"Onboarding_description": "Çalışma alanı, ekibinizin veya kuruluşunuzun işbirliği alanıdır. Çalışma alanı yöneticisinden bir ekibe katılmak veya bir ekip oluşturmak için yardım isteyin.",
|
||||
"Onboarding_join_workspace": "Bir çalışma alanına katılın",
|
||||
|
|
|
@ -350,7 +350,6 @@
|
|||
"Offline": "离线",
|
||||
"Oops": "哎呀!",
|
||||
"Omnichannel": "Omnichannel",
|
||||
"Open_Livechats": "打开即时聊天",
|
||||
"Omnichannel_enable_alert": "您尚未启用 Omnichannel,是否想要启用?",
|
||||
"Onboarding_description": "工作区是团队或组织协作的空间。向工作区管理员询问要加入的地址或为您的团队创建一个。",
|
||||
"Onboarding_join_workspace": "加入一个工作区",
|
||||
|
|
|
@ -352,7 +352,6 @@
|
|||
"Offline": "離線",
|
||||
"Oops": "哎呀!",
|
||||
"Omnichannel": "Omnichannel",
|
||||
"Open_Livechats": "打開即時聊天",
|
||||
"Omnichannel_enable_alert": "您尚未啟用 Omnichannel,是否想要啟用?",
|
||||
"Onboarding_description": "工作區是團隊或組織協作的空間。向工作區管理員詢問要加入的地址或為您的團隊創建一個。",
|
||||
"Onboarding_join_workspace": "加入一個工作區",
|
||||
|
|
|
@ -205,5 +205,11 @@ export const defaultSettings = {
|
|||
},
|
||||
Canned_Responses_Enable: {
|
||||
type: 'valueAsBoolean'
|
||||
},
|
||||
Livechat_allow_manual_on_hold: {
|
||||
type: 'valueAsBoolean'
|
||||
},
|
||||
Accounts_AvatarExternalProviderUrl: {
|
||||
type: 'valueAsString'
|
||||
}
|
||||
} as const;
|
||||
|
|
|
@ -83,4 +83,6 @@ export default class Message extends Model {
|
|||
@field('tshow') tshow;
|
||||
|
||||
@json('md', sanitizer) md;
|
||||
|
||||
@field('comment') comment;
|
||||
}
|
||||
|
|
|
@ -131,5 +131,7 @@ export default class Subscription extends Model {
|
|||
|
||||
@field('team_main') teamMain;
|
||||
|
||||
@field('on_hold') onHold;
|
||||
|
||||
@json('source', sanitizer) source;
|
||||
}
|
||||
|
|
|
@ -217,6 +217,19 @@ export default schemaMigrations({
|
|||
columns: [{ name: 'source', type: 'string', isOptional: true }]
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
toVersion: 17,
|
||||
steps: [
|
||||
addColumns({
|
||||
table: 'subscriptions',
|
||||
columns: [{ name: 'on_hold', type: 'boolean', isOptional: true }]
|
||||
}),
|
||||
addColumns({
|
||||
table: 'messages',
|
||||
columns: [{ name: 'comment', type: 'string', isOptional: true }]
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { appSchema, tableSchema } from '@nozbe/watermelondb';
|
||||
|
||||
export default appSchema({
|
||||
version: 16,
|
||||
version: 17,
|
||||
tables: [
|
||||
tableSchema({
|
||||
name: 'subscriptions',
|
||||
|
@ -60,6 +60,7 @@ export default appSchema({
|
|||
{ name: 'avatar_etag', type: 'string', isOptional: true },
|
||||
{ name: 'team_id', type: 'string', isIndexed: true },
|
||||
{ name: 'team_main', type: 'boolean', isOptional: true }, // Use `Q.notEq(true)` to get false or null
|
||||
{ name: 'on_hold', type: 'boolean', isOptional: true },
|
||||
{ name: 'source', type: 'string', isOptional: true }
|
||||
]
|
||||
}),
|
||||
|
@ -117,7 +118,8 @@ export default appSchema({
|
|||
{ name: 'blocks', type: 'string', isOptional: true },
|
||||
{ name: 'e2e', type: 'string', isOptional: true },
|
||||
{ name: 'tshow', type: 'boolean', isOptional: true },
|
||||
{ name: 'md', type: 'string', isOptional: true }
|
||||
{ name: 'md', type: 'string', isOptional: true },
|
||||
{ name: 'comment', type: 'string', isOptional: true }
|
||||
]
|
||||
}),
|
||||
tableSchema({
|
||||
|
|
|
@ -26,7 +26,8 @@ import {
|
|||
TMessageModel,
|
||||
TRoomModel,
|
||||
TThreadMessageModel,
|
||||
TThreadModel
|
||||
TThreadModel,
|
||||
SubscriptionType
|
||||
} from '../../../definitions';
|
||||
import sdk from '../../services/sdk';
|
||||
import { IDDPMessage } from '../../../definitions/IDDPMessage';
|
||||
|
@ -99,7 +100,8 @@ const createOrUpdateSubscription = async (subscription: ISubscription, room: ISe
|
|||
encrypted: s.encrypted,
|
||||
e2eKeyId: s.e2eKeyId,
|
||||
E2EKey: s.E2EKey,
|
||||
avatarETag: s.avatarETag
|
||||
avatarETag: s.avatarETag,
|
||||
onHold: s.onHold
|
||||
} as ISubscription;
|
||||
} catch (error) {
|
||||
try {
|
||||
|
@ -251,6 +253,11 @@ const debouncedUpdate = (subscription: ISubscription) => {
|
|||
createOrUpdateSubscription(sub, room);
|
||||
} else {
|
||||
const room = batch[key] as IRoom;
|
||||
// If the omnichannel's chat is onHold and waitingResponse we shouldn't create or update the chat,
|
||||
// because it should go to Queue
|
||||
if (room.t === SubscriptionType.OMNICHANNEL && room.onHold && room.waitingResponse) {
|
||||
return null;
|
||||
}
|
||||
const subQueueId = getSubQueueId(room._id);
|
||||
const sub = batch[subQueueId] as ISubscription;
|
||||
delete batch[subQueueId];
|
||||
|
|
|
@ -360,6 +360,8 @@ export const returnLivechat = (rid: string): Promise<boolean> =>
|
|||
// RC 0.72.0
|
||||
sdk.methodCallWrapper('livechat:returnAsInquiry', rid);
|
||||
|
||||
export const onHoldLivechat = (roomId: string) => sdk.post('livechat/room.onHold', { roomId });
|
||||
|
||||
export const forwardLivechat = (transferData: any) =>
|
||||
// RC 0.36.0
|
||||
sdk.methodCallWrapper('livechat:transfer', transferData);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { select, takeLatest } from 'redux-saga/effects';
|
||||
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import { setBadgeCount } from '../lib/notifications/push';
|
||||
import Push from '../lib/notifications/push';
|
||||
import log from '../utils/log';
|
||||
import { localAuthenticate, saveLastLocalAuthenticationSession } from '../utils/localAuthentication';
|
||||
import { APP_STATE } from '../actions/actionsTypes';
|
||||
|
@ -20,7 +20,7 @@ const appHasComeBackToForeground = function* appHasComeBackToForeground() {
|
|||
try {
|
||||
yield localAuthenticate(server.server);
|
||||
RocketChat.checkAndReopen();
|
||||
setBadgeCount();
|
||||
Push.setBadgeCount();
|
||||
return yield RocketChat.setUserPresenceOnline();
|
||||
} catch (e) {
|
||||
log(e);
|
||||
|
|
|
@ -2,7 +2,7 @@ import { SubscriptionType } from '../definitions/ISubscription';
|
|||
import { IAvatar } from '../containers/Avatar/interfaces';
|
||||
import { compareServerVersion } from '../lib/methods/helpers/compareServerVersion';
|
||||
|
||||
const formatUrl = (url: string, size: number, query: string) => `${url}?format=png&size=${size}${query}`;
|
||||
const formatUrl = (url: string, size: number, query?: string) => `${url}?format=png&size=${size}${query}`;
|
||||
|
||||
export const avatarURL = ({
|
||||
type,
|
||||
|
@ -14,11 +14,16 @@ export const avatarURL = ({
|
|||
avatarETag,
|
||||
rid,
|
||||
blockUnauthenticatedAccess,
|
||||
serverVersion
|
||||
serverVersion,
|
||||
externalProviderUrl
|
||||
}: IAvatar): string => {
|
||||
let room;
|
||||
if (type === SubscriptionType.DIRECT) {
|
||||
room = text;
|
||||
if (externalProviderUrl) {
|
||||
const externalUri = externalProviderUrl.trim().replace(/\/+$/, '').replace('{username}', room);
|
||||
return formatUrl(`${externalUri}`, size);
|
||||
}
|
||||
} else if (rid && !compareServerVersion(serverVersion, 'lowerThan', '3.6.0')) {
|
||||
room = `room/${rid}`;
|
||||
} else {
|
||||
|
|
|
@ -226,6 +226,7 @@ export default {
|
|||
ROOM_MSG_ACTION_REPORT: 'room_msg_action_report',
|
||||
ROOM_MSG_ACTION_REPORT_F: 'room_msg_action_report_f',
|
||||
ROOM_JOIN: 'room_join',
|
||||
ROOM_RESUME: 'room_resume',
|
||||
ROOM_GO_RA: 'room_go_ra',
|
||||
ROOM_TOGGLE_FOLLOW_THREADS: 'room_toggle_follow_threads',
|
||||
ROOM_GO_TEAM_CHANNELS: 'room_go_team_channels',
|
||||
|
|
|
@ -63,6 +63,7 @@ interface IRoomActionsViewProps extends IBaseScreen<ChatsStackParamList, 'RoomAc
|
|||
addTeamChannelPermission?: string[];
|
||||
convertTeamPermission?: string[];
|
||||
viewCannedResponsesPermission?: string[];
|
||||
livechatAllowManualOnHold?: boolean;
|
||||
}
|
||||
|
||||
interface IRoomActionsViewState {
|
||||
|
@ -82,6 +83,8 @@ interface IRoomActionsViewState {
|
|||
canAddChannelToTeam: boolean;
|
||||
canConvertTeam: boolean;
|
||||
canViewCannedResponse: boolean;
|
||||
canPlaceLivechatOnHold: boolean;
|
||||
isOnHold: boolean;
|
||||
}
|
||||
|
||||
class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomActionsViewState> {
|
||||
|
@ -129,13 +132,15 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
canCreateTeam: false,
|
||||
canAddChannelToTeam: false,
|
||||
canConvertTeam: false,
|
||||
canViewCannedResponse: false
|
||||
canViewCannedResponse: false,
|
||||
canPlaceLivechatOnHold: false,
|
||||
isOnHold: false
|
||||
};
|
||||
if (room && room.observe && room.rid) {
|
||||
this.roomObservable = room.observe();
|
||||
this.subscription = this.roomObservable.subscribe(changes => {
|
||||
if (this.mounted) {
|
||||
this.setState({ room: changes });
|
||||
this.setState({ room: changes, isOnHold: !!changes?.onHold });
|
||||
} else {
|
||||
// @ts-ignore
|
||||
this.state.room = changes;
|
||||
|
@ -209,11 +214,25 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
const canForwardGuest = await this.canForwardGuest();
|
||||
const canReturnQueue = await this.canReturnQueue();
|
||||
const canViewCannedResponse = await this.canViewCannedResponse();
|
||||
this.setState({ canForwardGuest, canReturnQueue, canViewCannedResponse });
|
||||
const canPlaceLivechatOnHold = this.canPlaceLivechatOnHold();
|
||||
this.setState({ canForwardGuest, canReturnQueue, canViewCannedResponse, canPlaceLivechatOnHold });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: IRoomActionsViewProps, prevState: IRoomActionsViewState) {
|
||||
const { livechatAllowManualOnHold } = this.props;
|
||||
const { room, isOnHold } = this.state;
|
||||
|
||||
if (
|
||||
room.t === 'l' &&
|
||||
(isOnHold !== prevState.isOnHold || prevProps.livechatAllowManualOnHold !== livechatAllowManualOnHold)
|
||||
) {
|
||||
const canPlaceLivechatOnHold = this.canPlaceLivechatOnHold();
|
||||
this.setState({ canPlaceLivechatOnHold });
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.subscription && this.subscription.unsubscribe) {
|
||||
this.subscription.unsubscribe();
|
||||
|
@ -360,6 +379,13 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
return permissions[0];
|
||||
};
|
||||
|
||||
canPlaceLivechatOnHold = (): boolean => {
|
||||
const { livechatAllowManualOnHold } = this.props;
|
||||
const { room } = this.state;
|
||||
|
||||
return !!(livechatAllowManualOnHold && !room?.lastMessage?.token && room?.lastMessage?.u && !room.onHold);
|
||||
};
|
||||
|
||||
canReturnQueue = async () => {
|
||||
try {
|
||||
const { returnQueue } = await RocketChat.getRoutingConfig();
|
||||
|
@ -393,6 +419,24 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
dispatch(closeRoom(rid));
|
||||
};
|
||||
|
||||
placeOnHoldLivechat = () => {
|
||||
const { navigation } = this.props;
|
||||
const { room } = this.state;
|
||||
showConfirmationAlert({
|
||||
title: I18n.t('Are_you_sure_question_mark'),
|
||||
message: I18n.t('Would_like_to_place_on_hold'),
|
||||
confirmationText: I18n.t('Yes'),
|
||||
onPress: async () => {
|
||||
try {
|
||||
await RocketChat.onHoldLivechat(room.rid);
|
||||
navigation.navigate('RoomsListView');
|
||||
} catch (e: any) {
|
||||
showErrorAlert(e.data?.error, I18n.t('Oops'));
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
returnLivechat = () => {
|
||||
const {
|
||||
room: { rid }
|
||||
|
@ -1005,7 +1049,8 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
canAutoTranslate,
|
||||
canForwardGuest,
|
||||
canReturnQueue,
|
||||
canViewCannedResponse
|
||||
canViewCannedResponse,
|
||||
canPlaceLivechatOnHold
|
||||
} = this.state;
|
||||
const { rid, t, prid } = room;
|
||||
const isGroupChat = RocketChat.isGroupChat(room);
|
||||
|
@ -1269,6 +1314,22 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
</>
|
||||
) : null}
|
||||
|
||||
{['l'].includes(t) && !this.isOmnichannelPreview && canPlaceLivechatOnHold ? (
|
||||
<>
|
||||
<List.Item
|
||||
title='Place_chat_on_hold'
|
||||
onPress={() =>
|
||||
this.onPressTouchable({
|
||||
event: this.placeOnHoldLivechat
|
||||
})
|
||||
}
|
||||
left={() => <List.Icon name='pause' />}
|
||||
showActionIndicator
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{['l'].includes(t) && !this.isOmnichannelPreview && canReturnQueue ? (
|
||||
<>
|
||||
<List.Item
|
||||
|
@ -1312,7 +1373,8 @@ const mapStateToProps = (state: IApplicationState) => ({
|
|||
createTeamPermission: state.permissions['create-team'],
|
||||
addTeamChannelPermission: state.permissions['add-team-channel'],
|
||||
convertTeamPermission: state.permissions['convert-team'],
|
||||
viewCannedResponsesPermission: state.permissions['view-canned-responses']
|
||||
viewCannedResponsesPermission: state.permissions['view-canned-responses'],
|
||||
livechatAllowManualOnHold: state.settings.Livechat_allow_manual_on_hold as boolean
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withTheme(withDimensions(RoomActionsView)));
|
||||
|
|
|
@ -46,7 +46,7 @@ import Navigation from '../../lib/navigation/appNavigation';
|
|||
import SafeAreaView from '../../containers/SafeAreaView';
|
||||
import { withDimensions } from '../../dimensions';
|
||||
import { getHeaderTitlePosition } from '../../containers/Header';
|
||||
import { takeInquiry } from '../../ee/omnichannel/lib';
|
||||
import { takeInquiry, takeResume } from '../../ee/omnichannel/lib';
|
||||
import Loading from '../../containers/Loading';
|
||||
import { goRoom, TGoRoomItem } from '../../utils/goRoom';
|
||||
import getThreadName from '../../lib/methods/getThreadName';
|
||||
|
@ -116,7 +116,8 @@ const roomAttrsUpdate = [
|
|||
'visitor',
|
||||
'joinCodeRequired',
|
||||
'teamMain',
|
||||
'teamId'
|
||||
'teamId',
|
||||
'onHold'
|
||||
] as const;
|
||||
|
||||
interface IRoomViewProps extends IBaseScreen<ChatsStackParamList, 'RoomView'> {
|
||||
|
@ -958,6 +959,22 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
}
|
||||
};
|
||||
|
||||
resumeRoom = async () => {
|
||||
logEvent(events.ROOM_RESUME);
|
||||
try {
|
||||
const { room } = this.state;
|
||||
|
||||
if (this.isOmnichannel) {
|
||||
if ('rid' in room) {
|
||||
await takeResume(room.rid);
|
||||
}
|
||||
this.onJoin();
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
getThreadName = (tmid: string, messageId: string) => {
|
||||
const { rid } = this.state.room;
|
||||
return getThreadName(rid, tmid, messageId);
|
||||
|
@ -1243,6 +1260,24 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
if (!this.rid) {
|
||||
return null;
|
||||
}
|
||||
if ('onHold' in room && room.onHold) {
|
||||
return (
|
||||
<View style={styles.joinRoomContainer} key='room-view-chat-on-hold' testID='room-view-chat-on-hold'>
|
||||
<Text accessibilityLabel={I18n.t('Chat_is_on_hold')} style={[styles.previewMode, { color: themes[theme].titleText }]}>
|
||||
{I18n.t('Chat_is_on_hold')}
|
||||
</Text>
|
||||
<Touch
|
||||
onPress={this.resumeRoom}
|
||||
style={[styles.joinRoomButton, { backgroundColor: themes[theme].actionTintColor }]}
|
||||
enabled={!loading}
|
||||
theme={theme}>
|
||||
<Text style={[styles.joinRoomText, { color: themes[theme].buttonText }]} testID='room-view-chat-on-hold-button'>
|
||||
{I18n.t('Resume')}
|
||||
</Text>
|
||||
</Touch>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
if (!joined && !this.tmid) {
|
||||
return (
|
||||
<View style={styles.joinRoomContainer} key='room-view-join' testID='room-view-join'>
|
||||
|
|
|
@ -10,7 +10,7 @@ import { StackNavigationOptions } from '@react-navigation/stack';
|
|||
|
||||
import database from '../../lib/database';
|
||||
import RocketChat from '../../lib/rocketchat';
|
||||
import RoomItem, { ROW_HEIGHT, ROW_HEIGHT_CONDENSED } from '../../presentation/RoomItem';
|
||||
import RoomItem, { ROW_HEIGHT, ROW_HEIGHT_CONDENSED } from '../../containers/RoomItem';
|
||||
import log, { logEvent, events } from '../../utils/log';
|
||||
import I18n from '../../i18n';
|
||||
import { closeSearchHeader, closeServerDropdown, openSearchHeader, roomsRequest } from '../../actions/rooms';
|
||||
|
@ -88,7 +88,8 @@ interface IRoomsListViewState {
|
|||
searching: boolean;
|
||||
search: ISubscription[];
|
||||
loading: boolean;
|
||||
chatsUpdate: [];
|
||||
chatsUpdate: string[];
|
||||
omnichannelsUpdate: string[];
|
||||
chats: ISubscription[];
|
||||
item: ISubscription;
|
||||
canCreateRoom: boolean;
|
||||
|
@ -107,7 +108,8 @@ const DISCUSSIONS_HEADER = 'Discussions';
|
|||
const TEAMS_HEADER = 'Teams';
|
||||
const CHANNELS_HEADER = 'Channels';
|
||||
const DM_HEADER = 'Direct_Messages';
|
||||
const OMNICHANNEL_HEADER = 'Open_Livechats';
|
||||
const OMNICHANNEL_HEADER_IN_PROGRESS = 'Open_Livechats';
|
||||
const OMNICHANNEL_HEADER_ON_HOLD = 'On_hold_Livechats';
|
||||
const QUERY_SIZE = 20;
|
||||
|
||||
const filterIsUnread = (s: TSubscriptionModel) => (s.unread > 0 || s.tunread?.length > 0 || s.alert) && !s.hideUnreadStatus;
|
||||
|
@ -172,6 +174,7 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
search: [],
|
||||
loading: true,
|
||||
chatsUpdate: [],
|
||||
omnichannelsUpdate: [],
|
||||
chats: [],
|
||||
item: {} as ISubscription,
|
||||
canCreateRoom: false
|
||||
|
@ -231,7 +234,7 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
}
|
||||
|
||||
shouldComponentUpdate(nextProps: IRoomsListViewProps, nextState: IRoomsListViewState) {
|
||||
const { chatsUpdate, searching, item, canCreateRoom } = this.state;
|
||||
const { chatsUpdate, searching, item, canCreateRoom, omnichannelsUpdate } = this.state;
|
||||
// eslint-disable-next-line react/destructuring-assignment
|
||||
const propsUpdated = shouldUpdateProps.some(key => nextProps[key] !== this.props[key]);
|
||||
if (propsUpdated) {
|
||||
|
@ -260,6 +263,12 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
this.shouldUpdate = true;
|
||||
}
|
||||
|
||||
const omnichannelsNotEqual = !dequal(nextState.omnichannelsUpdate, omnichannelsUpdate);
|
||||
|
||||
if (omnichannelsNotEqual) {
|
||||
this.shouldUpdate = true;
|
||||
}
|
||||
|
||||
if (nextState.searching !== searching) {
|
||||
return true;
|
||||
}
|
||||
|
@ -295,7 +304,7 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
return true;
|
||||
}
|
||||
// If it's focused and there are changes, update
|
||||
if (chatsNotEqual) {
|
||||
if (chatsNotEqual || omnichannelsNotEqual) {
|
||||
this.shouldUpdate = false;
|
||||
return true;
|
||||
}
|
||||
|
@ -480,21 +489,21 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
observable = await db
|
||||
.get('subscriptions')
|
||||
.query(...defaultWhereClause)
|
||||
.observeWithColumns(['alert']);
|
||||
|
||||
.observeWithColumns(['alert', 'on_hold']);
|
||||
// When we're NOT grouping
|
||||
} else {
|
||||
this.count += QUERY_SIZE;
|
||||
observable = await db
|
||||
.get('subscriptions')
|
||||
.query(...defaultWhereClause, Q.experimentalSkip(0), Q.experimentalTake(this.count))
|
||||
.observe();
|
||||
.observeWithColumns(['on_hold']);
|
||||
}
|
||||
|
||||
this.querySubscription = observable.subscribe(data => {
|
||||
let tempChats = [] as TSubscriptionModel[];
|
||||
let chats = data;
|
||||
|
||||
let omnichannelsUpdate: string[] = [];
|
||||
let chatsUpdate = [];
|
||||
if (showUnread) {
|
||||
/**
|
||||
|
@ -513,8 +522,12 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
const isOmnichannelAgent = user?.roles?.includes('livechat-agent');
|
||||
if (isOmnichannelAgent) {
|
||||
const omnichannel = chats.filter(s => filterIsOmnichannel(s));
|
||||
const omnichannelInProgress = omnichannel.filter(s => !s.onHold);
|
||||
const omnichannelOnHold = omnichannel.filter(s => s.onHold);
|
||||
chats = chats.filter(s => !filterIsOmnichannel(s));
|
||||
tempChats = this.addRoomsGroup(omnichannel, OMNICHANNEL_HEADER, tempChats);
|
||||
omnichannelsUpdate = omnichannelInProgress.map(s => s.rid);
|
||||
tempChats = this.addRoomsGroup(omnichannelInProgress, OMNICHANNEL_HEADER_IN_PROGRESS, tempChats);
|
||||
tempChats = this.addRoomsGroup(omnichannelOnHold, OMNICHANNEL_HEADER_ON_HOLD, tempChats);
|
||||
}
|
||||
|
||||
// unread
|
||||
|
@ -551,6 +564,7 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
this.internalSetState({
|
||||
chats: tempChats,
|
||||
chatsUpdate,
|
||||
omnichannelsUpdate,
|
||||
loading: false
|
||||
});
|
||||
} else {
|
||||
|
@ -559,6 +573,8 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
// @ts-ignore
|
||||
this.state.chatsUpdate = chatsUpdate;
|
||||
// @ts-ignore
|
||||
this.state.omnichannelsUpdate = omnichannelsUpdate;
|
||||
// @ts-ignore
|
||||
this.state.loading = false;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -24,7 +24,7 @@ import I18n from '../i18n';
|
|||
import database from '../lib/database';
|
||||
import { CustomIcon } from '../lib/Icons';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import RoomItem, { ROW_HEIGHT } from '../presentation/RoomItem';
|
||||
import RoomItem, { ROW_HEIGHT } from '../containers/RoomItem';
|
||||
import { getUserSelector } from '../selectors/login';
|
||||
import { ChatsStackParamList } from '../stacks/types';
|
||||
import { TSupportedThemes, withTheme } from '../theme';
|
||||
|
|
|
@ -1683,7 +1683,7 @@
|
|||
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||
MARKETING_VERSION = 4.26.2;
|
||||
MARKETING_VERSION = 4.27.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService;
|
||||
|
@ -1720,7 +1720,7 @@
|
|||
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||
MARKETING_VERSION = 4.26.2;
|
||||
MARKETING_VERSION = 4.27.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.26.2</string>
|
||||
<string>4.27.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.26.2</string>
|
||||
<string>4.27.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>KeychainGroup</key>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "rocket-chat-reactnative",
|
||||
"version": "4.26.2",
|
||||
"version": "4.27.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "react-native start",
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Dimensions, ScrollView } from 'react-native';
|
|||
import { storiesOf } from '@storybook/react-native';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
import RoomItemComponent from '../../app/presentation/RoomItem/RoomItem';
|
||||
import RoomItemComponent from '../../app/containers/RoomItem/RoomItem';
|
||||
import { longText } from '../utils';
|
||||
import { DisplayMode, themes } from '../../app/lib/constants';
|
||||
import { store } from './index';
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue