feat: Refactor Status to make it handle user presence requests (#5148)

This commit is contained in:
Diego Mello 2023-08-29 16:15:26 -03:00 committed by GitHub
parent 7e7d42780f
commit 024088dca6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 161 additions and 147 deletions

View File

@ -33,8 +33,10 @@ const getStories = () => {
require("../app/containers/ReactionsList/ReactionsList.stories.tsx"),
require("../app/containers/RoomHeader/RoomHeader.stories.tsx"),
require("../app/containers/RoomItem/RoomItem.stories.tsx"),
require("../app/containers/RoomTypeIcon/RoomTypeIcon.stories.tsx"),
require("../app/containers/SearchBox/SearchBox.stories.tsx"),
require("../app/containers/ServerItem/ServerItem.stories.tsx"),
require("../app/containers/Status/Status.stories.tsx"),
require("../app/containers/TextInput/TextInput.stories.tsx"),
require("../app/containers/UIKit/UiKitMessage.stories.tsx"),
require("../app/containers/UIKit/UiKitModal.stories.tsx"),

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Storyshots RoomTypeIcon All 1`] = `"[{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":30,\\"color\\":\\"#cbced1\\"},[{\\"width\\":30,\\"height\\":30,\\"textAlignVertical\\":\\"center\\"},[{\\"marginRight\\":4},null]],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":30,\\"color\\":\\"#2de0a5\\"},[{\\"width\\":30,\\"height\\":30,\\"textAlignVertical\\":\\"center\\"},[{\\"marginRight\\":4},null]],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":30,\\"color\\":\\"#0d0e12\\"},[{\\"marginRight\\":4},null],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":30,\\"color\\":\\"#0d0e12\\"},[{\\"marginRight\\":4},null],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":30,\\"color\\":\\"#0d0e12\\"},[{\\"marginRight\\":4},null],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":30,\\"color\\":\\"#0d0e12\\"},[{\\"marginRight\\":4},null],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":30,\\"color\\":\\"#0d0e12\\"},[{\\"marginRight\\":4},null],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":30,\\"color\\":\\"#0d0e12\\"},[{\\"marginRight\\":4},null],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":30,\\"color\\":\\"#ffd21f\\"},[{\\"marginRight\\":4},null],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":30,\\"color\\":\\"#0d0e12\\"},[{\\"marginRight\\":4},{\\"margin\\":10}],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]}]"`;

View File

@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Storyshots Status All 1`] = `"[{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":32,\\"color\\":\\"#2de0a5\\"},[{\\"width\\":32,\\"height\\":32,\\"textAlignVertical\\":\\"center\\"},null],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":32,\\"color\\":\\"#f5455c\\"},[{\\"width\\":32,\\"height\\":32,\\"textAlignVertical\\":\\"center\\"},null],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":32,\\"color\\":\\"#ffd21f\\"},[{\\"width\\":32,\\"height\\":32,\\"textAlignVertical\\":\\"center\\"},null],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":32,\\"color\\":\\"#9ea2a8\\"},[{\\"width\\":32,\\"height\\":32,\\"textAlignVertical\\":\\"center\\"},null],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":32,\\"color\\":\\"#F38C39\\"},[{\\"width\\":32,\\"height\\":32,\\"textAlignVertical\\":\\"center\\"},null],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":32,\\"color\\":\\"#cbced1\\"},[{\\"width\\":32,\\"height\\":32,\\"textAlignVertical\\":\\"center\\"},null],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":32,\\"color\\":\\"#cbced1\\"},[{\\"width\\":32,\\"height\\":32,\\"textAlignVertical\\":\\"center\\"},null],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":60,\\"color\\":\\"#2de0a5\\"},[{\\"width\\":60,\\"height\\":60,\\"textAlignVertical\\":\\"center\\"},null],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]}]"`;

View File

@ -63,10 +63,11 @@ interface IRoomHeader {
type: string;
width: number;
height: number;
roomUserId?: string | null;
prid?: string;
tmid?: string;
teamMain?: boolean;
status: TUserStatus;
status?: TUserStatus;
usersTyping: [];
isGroupChat?: boolean;
parentTitle?: string;
@ -130,6 +131,7 @@ const Header = React.memo(
status,
width,
height,
roomUserId,
prid,
tmid,
onPress,
@ -154,7 +156,13 @@ const Header = React.memo(
if (tmid) {
renderFunc = () => (
<View style={styles.titleContainer}>
<RoomTypeIcon type={prid ? 'discussion' : type} isGroupChat={isGroupChat} status={status} teamMain={teamMain} />
<RoomTypeIcon
userId={roomUserId}
type={prid ? 'discussion' : type}
isGroupChat={isGroupChat}
status={status}
teamMain={teamMain}
/>
<Text style={[styles.subtitle, { color: colors.auxiliaryText }]} numberOfLines={1}>
{parentTitle}
</Text>
@ -176,6 +184,7 @@ const Header = React.memo(
<View style={styles.titleContainer}>
{tmid ? null : (
<RoomTypeIcon
userId={roomUserId}
type={prid ? 'discussion' : type}
isGroupChat={isGroupChat}
status={status}

View File

@ -39,14 +39,13 @@ const RoomHeaderContainer = React.memo(
visitor
}: IRoomHeaderContainerProps) => {
let subtitle: string | undefined;
let status: TUserStatus = 'offline';
let statusVisitor: TUserStatus | undefined;
let statusText: string | undefined;
const { width, height } = useDimensions();
const connecting = useSelector((state: IApplicationState) => state.meteor.connecting || state.server.loading);
const usersTyping = useSelector((state: IApplicationState) => state.usersTyping, shallowEqual);
const connected = useSelector((state: IApplicationState) => state.meteor.connected);
const presenceDisabled = useSelector((state: IApplicationState) => state.settings.Presence_broadcast_disabled);
const activeUser = useSelector(
(state: IApplicationState) => (roomUserId ? state.activeUsers?.[roomUserId] : undefined),
shallowEqual
@ -62,28 +61,23 @@ const RoomHeaderContainer = React.memo(
if (connected) {
if ((type === 'd' || (tmid && roomUserId)) && activeUser) {
if (presenceDisabled) {
status = 'disabled';
} else {
const { status: statusActiveUser, statusText: statusTextActiveUser } = activeUser;
status = statusActiveUser;
statusText = statusTextActiveUser;
}
const { statusText: statusTextActiveUser } = activeUser;
statusText = statusTextActiveUser;
} else if (type === 'l' && visitor?.status) {
const { status: statusVisitor } = visitor;
status = statusVisitor;
({ status: statusVisitor } = visitor);
}
}
return (
<RoomHeader
roomUserId={roomUserId}
prid={prid}
tmid={tmid}
title={title}
subtitle={type === 'd' ? statusText : subtitle}
type={type}
teamMain={teamMain}
status={status}
status={statusVisitor}
width={width}
height={height}
usersTyping={usersTyping}

View File

@ -12,6 +12,7 @@ const IconOrAvatar = ({
type,
rid,
showAvatar,
userId,
prid,
status,
isGroupChat,
@ -30,6 +31,7 @@ const IconOrAvatar = ({
return (
<View style={styles.typeIcon}>
<TypeIcon
userId={userId}
type={type}
prid={prid}
status={status}

View File

@ -41,14 +41,14 @@ export const Touch = () => <RoomItem onPress={() => alert('on press')} onLongPre
export const User = () => (
<>
<RoomItem name='diego.mello' avatar='diego.mello' />
<RoomItem name={longText} />
<RoomItem name='diego.mello' avatar='diego.mello' userId='abc' />
<RoomItem name={longText} userId='abc' />
</>
);
export const Type = () => (
<>
<RoomItem type='d' />
<RoomItem type='d' userId='abc' />
<RoomItem type='c' />
<RoomItem type='p' />
<RoomItem type='l' />
@ -58,18 +58,6 @@ export const Type = () => (
</>
);
export const UserStatus = () => (
<>
<RoomItem status='online' />
<RoomItem status='away' />
<RoomItem status='busy' />
<RoomItem status='offline' />
<RoomItem status='loading' />
<RoomItem status='disabled' />
<RoomItem status='wrong' />
</>
);
export const Alerts = () => (
<>
<RoomItem alert />
@ -159,7 +147,6 @@ export const ExpandedRoomItemWithoutAvatar = () => (
showAvatar={false}
/>
<RoomItem
status='online'
showLastMessage
alert
tunread={[1]}
@ -167,14 +154,7 @@ export const ExpandedRoomItemWithoutAvatar = () => (
displayMode={DisplayMode.Expanded}
showAvatar={false}
/>
<RoomItem
status='online'
showLastMessage
alert
lastMessage={lastMessage}
displayMode={DisplayMode.Expanded}
showAvatar={false}
/>
<RoomItem showLastMessage alert lastMessage={lastMessage} displayMode={DisplayMode.Expanded} showAvatar={false} />
</>
);

View File

@ -16,6 +16,7 @@ import { IRoomItemProps } from './interfaces';
const RoomItem = ({
rid,
userId,
type,
prid,
name,
@ -74,6 +75,7 @@ const RoomItem = ({
accessibilityLabel={accessibilityLabel}
avatar={avatar}
type={type}
userId={userId}
rid={rid}
prid={prid}
status={status}
@ -89,6 +91,7 @@ const RoomItem = ({
<View style={styles.titleContainer}>
{showAvatar ? (
<TypeIcon
userId={userId}
type={type}
prid={prid}
status={status}
@ -125,6 +128,7 @@ const RoomItem = ({
) : (
<View style={[styles.titleContainer, styles.flex]}>
<TypeIcon
userId={userId}
type={type}
prid={prid}
status={status}

View File

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

View File

@ -2,13 +2,11 @@ import React, { useEffect, useReducer, useRef } from 'react';
import { Subscription } from 'rxjs';
import I18n from '../../i18n';
import { getUserPresence } from '../../lib/methods';
import { isGroupChat } from '../../lib/methods/helpers';
import { formatDate } from '../../lib/methods/helpers/room';
import { IRoomItemContainerProps } from './interfaces';
import RoomItem from './RoomItem';
import { ROW_HEIGHT, ROW_HEIGHT_CONDENSED } from './styles';
import { useUserStatus } from './useUserStatus';
export { ROW_HEIGHT, ROW_HEIGHT_CONDENSED };
@ -44,8 +42,7 @@ const RoomItemContainer = React.memo(
const alert = item.alert || item.tunread?.length;
const [_, forceUpdate] = useReducer(x => x + 1, 1);
const roomSubscription = useRef<Subscription | null>(null);
const { connected, status } = useUserStatus(item.t, item?.visitor?.status, id);
const userId = item.t === 'd' && id && !isGroupChat(item) ? id : null;
useEffect(() => {
const init = () => {
@ -61,13 +58,6 @@ const RoomItemContainer = React.memo(
return () => roomSubscription.current?.unsubscribe();
}, []);
useEffect(() => {
const isDirect = !!(item.t === 'd' && id && !isGroupChat(item));
if (connected && isDirect) {
getUserPresence(id);
}
}, [connected]);
const handleOnPress = () => onPress(item);
const handleOnLongPress = () => onLongPress && onLongPress(item);
@ -98,6 +88,7 @@ const RoomItemContainer = React.memo(
width={width}
favorite={item.f}
rid={item.rid}
userId={userId}
toggleFav={toggleFav}
toggleRead={toggleRead}
hideChannel={hideChannel}
@ -105,7 +96,6 @@ const RoomItemContainer = React.memo(
type={item.t}
isFocused={isFocused}
prid={item.prid}
status={status}
hideUnreadStatus={item.hideUnreadStatus}
hideMentionStatus={item.hideMentionStatus}
alert={alert}
@ -124,7 +114,8 @@ const RoomItemContainer = React.memo(
autoJoin={autoJoin}
showAvatar={showAvatar}
displayMode={displayMode}
sourceType={item.source}
status={item.t === 'l' ? item?.visitor?.status : null}
sourceType={item.t === 'l' ? item.source : null}
/>
);
},

View File

@ -37,6 +37,7 @@ export interface IWrapperProps {
accessibilityLabel: string;
avatar: string;
type: string;
userId: string | null;
rid: string;
children: React.ReactElement;
displayMode: string;
@ -50,6 +51,7 @@ export interface IWrapperProps {
}
export interface ITypeIconProps {
userId: string | null;
type: string;
status: TUserStatus;
prid: string;
@ -144,6 +146,7 @@ export interface IIconOrAvatar {
avatar: string;
type: string;
rid: string;
userId: string | null;
showAvatar: boolean;
displayMode: string;
prid: string;

View File

@ -1,30 +0,0 @@
import { TUserStatus } from '../../definitions';
import { useAppSelector } from '../../lib/hooks';
import { RoomTypes } from '../../lib/methods';
export const useUserStatus = (
type: RoomTypes,
liveChatStatus?: TUserStatus,
id?: string
): { connected: boolean; status: TUserStatus } => {
const connected = useAppSelector(state => state.meteor.connected);
const presenceDisabled = useAppSelector(state => state.settings.Presence_broadcast_disabled);
const userStatus = useAppSelector(state => state.activeUsers[id || '']?.status);
let status = 'loading';
if (connected) {
if (type === 'd') {
if (presenceDisabled) {
status = 'disabled';
} else {
status = userStatus || 'loading';
}
} else if (type === 'l' && liveChatStatus) {
status = liveChatStatus;
}
}
return {
connected,
status: status as TUserStatus
};
};

View File

@ -0,0 +1,23 @@
import React from 'react';
import { OmnichannelSourceType } from '../../definitions';
import RoomTypeIcon from '.';
export default {
title: 'RoomTypeIcon'
};
export const All = () => (
<>
<RoomTypeIcon size={30} type='d' userId='asd' />
<RoomTypeIcon size={30} type='d' userId='asd' status='online' />
<RoomTypeIcon size={30} type='d' isGroupChat />
<RoomTypeIcon size={30} type='c' />
<RoomTypeIcon size={30} type='p' />
<RoomTypeIcon size={30} type='c' teamMain />
<RoomTypeIcon size={30} type='p' teamMain />
<RoomTypeIcon size={30} type='discussion' />
<RoomTypeIcon size={30} type='l' status='away' sourceType={{ type: OmnichannelSourceType.SMS }} />
<RoomTypeIcon size={30} type='p' style={{ margin: 10 }} />
</>
);

View File

@ -3,8 +3,8 @@ import { StyleSheet, ViewStyle } from 'react-native';
import { OmnichannelRoomIcon } from './OmnichannelRoomIcon';
import { CustomIcon, TIconsName } from '../CustomIcon';
import { STATUS_COLORS, themes } from '../../lib/constants';
import Status from '../Status/Status';
import { themes } from '../../lib/constants';
import Status from '../Status';
import { useTheme } from '../../theme';
import { TUserStatus, IOmnichannelSource } from '../../definitions';
@ -15,6 +15,7 @@ const styles = StyleSheet.create({
});
interface IRoomTypeIcon {
userId?: string | null;
type: string;
isGroupChat?: boolean;
teamMain?: boolean;
@ -24,44 +25,38 @@ interface IRoomTypeIcon {
sourceType?: IOmnichannelSource;
}
const RoomTypeIcon = React.memo(({ type, isGroupChat, status, style, teamMain, size = 16, sourceType }: IRoomTypeIcon) => {
const { theme } = useTheme();
const RoomTypeIcon = React.memo(
({ userId, type, isGroupChat, status, style, teamMain, size = 16, sourceType }: IRoomTypeIcon) => {
const { theme } = useTheme();
if (!type) {
return null;
}
const color = themes[theme].titleText;
const iconStyle = [styles.icon, { color }, style];
if (type === 'd' && !isGroupChat) {
if (!status) {
status = 'offline';
if (!type) {
return null;
}
return <Status style={[iconStyle, { color: STATUS_COLORS[status] }]} size={size} status={status} />;
}
if (type === 'l') {
return <OmnichannelRoomIcon style={[styles.icon, style]} size={size} type={type} status={status} sourceType={sourceType} />;
}
const iconStyle = [styles.icon, style];
// TODO: move this to a separate function
let icon: TIconsName = 'channel-private';
if (teamMain) {
icon = `teams${type === 'p' ? '-private' : ''}`;
} else if (type === 'discussion') {
icon = 'discussions';
} else if (type === 'c') {
icon = 'channel-public';
} else if (type === 'd') {
if (isGroupChat) {
if (type === 'd' && !isGroupChat && userId) {
return <Status id={userId} style={iconStyle} size={size} status={status} />;
}
if (type === 'l') {
return <OmnichannelRoomIcon style={iconStyle} size={size} type={type} status={status} sourceType={sourceType} />;
}
// TODO: move this to a separate function
let icon: TIconsName = 'channel-private';
if (teamMain) {
icon = `teams${type === 'p' ? '-private' : ''}`;
} else if (type === 'discussion') {
icon = 'discussions';
} else if (type === 'c') {
icon = 'channel-public';
} else if (type === 'd' && isGroupChat) {
icon = 'message';
} else {
icon = 'mention';
}
}
return <CustomIcon name={icon} size={size} color={color} style={iconStyle} />;
});
return <CustomIcon name={icon} size={size} color={themes[theme].titleText} style={iconStyle} />;
}
);
export default RoomTypeIcon;

View File

@ -0,0 +1,20 @@
import React from 'react';
import Status from './Status';
export default {
title: 'Status'
};
export const All = () => (
<>
<Status status='online' />
<Status status='busy' />
<Status status='away' />
<Status status='loading' />
<Status status='disabled' />
<Status status='offline' />
<Status />
<Status status='online' size={60} />
</>
);

View File

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

View File

@ -5,5 +5,10 @@ import { TUserStatus } from '../../definitions';
export interface IStatus extends TextProps {
id: string;
size: number;
status: TUserStatus;
status?: TUserStatus | null;
}
export interface IStatusComponentProps extends Omit<IStatus, 'id' | 'size' | 'status'> {
size?: number;
status?: TUserStatus;
}

View File

@ -1,21 +1,32 @@
import React from 'react';
import React, { useEffect } from 'react';
import { TUserStatus } from '../../definitions';
import Status from './Status';
import { IStatus } from './definition';
import { useAppSelector } from '../../lib/hooks';
import { getUserPresence } from '../../lib/methods';
const StatusContainer = ({ id, style, size = 32, ...props }: Omit<IStatus, 'status'>): React.ReactElement => {
const status = useAppSelector(state => {
const StatusContainer = ({ id, style, status, size = 32, ...props }: IStatus): React.ReactElement => {
const connected = useAppSelector(state => state.meteor.connected);
const statusState = useAppSelector(state => {
if (state.settings.Presence_broadcast_disabled) {
return 'disabled';
}
if (state.meteor.connected) {
return state.activeUsers[id] && state.activeUsers[id].status;
if (state.meteor.connected && state.activeUsers[id]) {
return state.activeUsers[id].status;
}
if (!state.meteor.connected) {
return 'offline';
}
return 'loading';
}) as TUserStatus;
return <Status size={size} style={style} status={status} {...props} />;
});
useEffect(() => {
if (connected && statusState === 'loading') {
getUserPresence(id);
}
}, [connected, statusState]);
return <Status size={size} style={style} status={status ?? statusState} {...props} />;
};
export default StatusContainer;

View File

@ -1,3 +1,3 @@
export const STATUSES = ['offline', 'online', 'away', 'busy', 'disabled'] as const;
export const STATUSES = ['offline', 'online', 'away', 'busy', 'disabled', 'loading'] as const;
export type TUserStatus = typeof STATUSES[number];

View File

@ -952,7 +952,7 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
showAvatar,
displayMode
} = this.props;
const id = getUidDirectMessage(item);
const id = item.search && item.t === 'd' ? item._id : getUidDirectMessage(item);
const swipeEnabled = this.isSwipeEnabled(item);
return (