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/ReactionsList/ReactionsList.stories.tsx"),
require("../app/containers/RoomHeader/RoomHeader.stories.tsx"), require("../app/containers/RoomHeader/RoomHeader.stories.tsx"),
require("../app/containers/RoomItem/RoomItem.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/SearchBox/SearchBox.stories.tsx"),
require("../app/containers/ServerItem/ServerItem.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/TextInput/TextInput.stories.tsx"),
require("../app/containers/UIKit/UiKitMessage.stories.tsx"), require("../app/containers/UIKit/UiKitMessage.stories.tsx"),
require("../app/containers/UIKit/UiKitModal.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; type: string;
width: number; width: number;
height: number; height: number;
roomUserId?: string | null;
prid?: string; prid?: string;
tmid?: string; tmid?: string;
teamMain?: boolean; teamMain?: boolean;
status: TUserStatus; status?: TUserStatus;
usersTyping: []; usersTyping: [];
isGroupChat?: boolean; isGroupChat?: boolean;
parentTitle?: string; parentTitle?: string;
@ -130,6 +131,7 @@ const Header = React.memo(
status, status,
width, width,
height, height,
roomUserId,
prid, prid,
tmid, tmid,
onPress, onPress,
@ -154,7 +156,13 @@ const Header = React.memo(
if (tmid) { if (tmid) {
renderFunc = () => ( renderFunc = () => (
<View style={styles.titleContainer}> <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}> <Text style={[styles.subtitle, { color: colors.auxiliaryText }]} numberOfLines={1}>
{parentTitle} {parentTitle}
</Text> </Text>
@ -176,6 +184,7 @@ const Header = React.memo(
<View style={styles.titleContainer}> <View style={styles.titleContainer}>
{tmid ? null : ( {tmid ? null : (
<RoomTypeIcon <RoomTypeIcon
userId={roomUserId}
type={prid ? 'discussion' : type} type={prid ? 'discussion' : type}
isGroupChat={isGroupChat} isGroupChat={isGroupChat}
status={status} status={status}

View File

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

View File

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

View File

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

View File

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

View File

@ -3,8 +3,9 @@ import React from 'react';
import RoomTypeIcon from '../RoomTypeIcon'; import RoomTypeIcon from '../RoomTypeIcon';
import { ITypeIconProps } from './interfaces'; 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 <RoomTypeIcon
userId={userId}
type={prid ? 'discussion' : type} type={prid ? 'discussion' : type}
isGroupChat={isGroupChat} isGroupChat={isGroupChat}
status={status} status={status}

View File

@ -2,13 +2,11 @@ import React, { useEffect, useReducer, useRef } from 'react';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import I18n from '../../i18n'; import I18n from '../../i18n';
import { getUserPresence } from '../../lib/methods';
import { isGroupChat } from '../../lib/methods/helpers'; import { isGroupChat } from '../../lib/methods/helpers';
import { formatDate } from '../../lib/methods/helpers/room'; import { formatDate } from '../../lib/methods/helpers/room';
import { IRoomItemContainerProps } from './interfaces'; import { IRoomItemContainerProps } from './interfaces';
import RoomItem from './RoomItem'; import RoomItem from './RoomItem';
import { ROW_HEIGHT, ROW_HEIGHT_CONDENSED } from './styles'; import { ROW_HEIGHT, ROW_HEIGHT_CONDENSED } from './styles';
import { useUserStatus } from './useUserStatus';
export { ROW_HEIGHT, ROW_HEIGHT_CONDENSED }; export { ROW_HEIGHT, ROW_HEIGHT_CONDENSED };
@ -44,8 +42,7 @@ const RoomItemContainer = React.memo(
const alert = item.alert || item.tunread?.length; const alert = item.alert || item.tunread?.length;
const [_, forceUpdate] = useReducer(x => x + 1, 1); const [_, forceUpdate] = useReducer(x => x + 1, 1);
const roomSubscription = useRef<Subscription | null>(null); const roomSubscription = useRef<Subscription | null>(null);
const userId = item.t === 'd' && id && !isGroupChat(item) ? id : null;
const { connected, status } = useUserStatus(item.t, item?.visitor?.status, id);
useEffect(() => { useEffect(() => {
const init = () => { const init = () => {
@ -61,13 +58,6 @@ const RoomItemContainer = React.memo(
return () => roomSubscription.current?.unsubscribe(); return () => roomSubscription.current?.unsubscribe();
}, []); }, []);
useEffect(() => {
const isDirect = !!(item.t === 'd' && id && !isGroupChat(item));
if (connected && isDirect) {
getUserPresence(id);
}
}, [connected]);
const handleOnPress = () => onPress(item); const handleOnPress = () => onPress(item);
const handleOnLongPress = () => onLongPress && onLongPress(item); const handleOnLongPress = () => onLongPress && onLongPress(item);
@ -98,6 +88,7 @@ const RoomItemContainer = React.memo(
width={width} width={width}
favorite={item.f} favorite={item.f}
rid={item.rid} rid={item.rid}
userId={userId}
toggleFav={toggleFav} toggleFav={toggleFav}
toggleRead={toggleRead} toggleRead={toggleRead}
hideChannel={hideChannel} hideChannel={hideChannel}
@ -105,7 +96,6 @@ const RoomItemContainer = React.memo(
type={item.t} type={item.t}
isFocused={isFocused} isFocused={isFocused}
prid={item.prid} prid={item.prid}
status={status}
hideUnreadStatus={item.hideUnreadStatus} hideUnreadStatus={item.hideUnreadStatus}
hideMentionStatus={item.hideMentionStatus} hideMentionStatus={item.hideMentionStatus}
alert={alert} alert={alert}
@ -124,7 +114,8 @@ const RoomItemContainer = React.memo(
autoJoin={autoJoin} autoJoin={autoJoin}
showAvatar={showAvatar} showAvatar={showAvatar}
displayMode={displayMode} 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; accessibilityLabel: string;
avatar: string; avatar: string;
type: string; type: string;
userId: string | null;
rid: string; rid: string;
children: React.ReactElement; children: React.ReactElement;
displayMode: string; displayMode: string;
@ -50,6 +51,7 @@ export interface IWrapperProps {
} }
export interface ITypeIconProps { export interface ITypeIconProps {
userId: string | null;
type: string; type: string;
status: TUserStatus; status: TUserStatus;
prid: string; prid: string;
@ -144,6 +146,7 @@ export interface IIconOrAvatar {
avatar: string; avatar: string;
type: string; type: string;
rid: string; rid: string;
userId: string | null;
showAvatar: boolean; showAvatar: boolean;
displayMode: string; displayMode: string;
prid: 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 { OmnichannelRoomIcon } from './OmnichannelRoomIcon';
import { CustomIcon, TIconsName } from '../CustomIcon'; import { CustomIcon, TIconsName } from '../CustomIcon';
import { STATUS_COLORS, themes } from '../../lib/constants'; import { themes } from '../../lib/constants';
import Status from '../Status/Status'; import Status from '../Status';
import { useTheme } from '../../theme'; import { useTheme } from '../../theme';
import { TUserStatus, IOmnichannelSource } from '../../definitions'; import { TUserStatus, IOmnichannelSource } from '../../definitions';
@ -15,6 +15,7 @@ const styles = StyleSheet.create({
}); });
interface IRoomTypeIcon { interface IRoomTypeIcon {
userId?: string | null;
type: string; type: string;
isGroupChat?: boolean; isGroupChat?: boolean;
teamMain?: boolean; teamMain?: boolean;
@ -24,44 +25,38 @@ interface IRoomTypeIcon {
sourceType?: IOmnichannelSource; sourceType?: IOmnichannelSource;
} }
const RoomTypeIcon = React.memo(({ type, isGroupChat, status, style, teamMain, size = 16, sourceType }: IRoomTypeIcon) => { const RoomTypeIcon = React.memo(
const { theme } = useTheme(); ({ userId, type, isGroupChat, status, style, teamMain, size = 16, sourceType }: IRoomTypeIcon) => {
const { theme } = useTheme();
if (!type) { if (!type) {
return null; return null;
}
const color = themes[theme].titleText;
const iconStyle = [styles.icon, { color }, style];
if (type === 'd' && !isGroupChat) {
if (!status) {
status = 'offline';
} }
return <Status style={[iconStyle, { color: STATUS_COLORS[status] }]} size={size} status={status} />;
}
if (type === 'l') { const iconStyle = [styles.icon, style];
return <OmnichannelRoomIcon style={[styles.icon, style]} size={size} type={type} status={status} sourceType={sourceType} />;
}
// TODO: move this to a separate function if (type === 'd' && !isGroupChat && userId) {
let icon: TIconsName = 'channel-private'; return <Status id={userId} style={iconStyle} size={size} status={status} />;
if (teamMain) { }
icon = `teams${type === 'p' ? '-private' : ''}`;
} else if (type === 'discussion') { if (type === 'l') {
icon = 'discussions'; return <OmnichannelRoomIcon style={iconStyle} size={size} type={type} status={status} sourceType={sourceType} />;
} else if (type === 'c') { }
icon = 'channel-public';
} else if (type === 'd') { // TODO: move this to a separate function
if (isGroupChat) { 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'; 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; 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 { CustomIcon, IconSet, TIconsName } from '../CustomIcon';
import { STATUS_COLORS } from '../../lib/constants'; 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 name: TIconsName = `status-${status}`;
const isNameValid = IconSet.hasIcon(name); const isNameValid = IconSet.hasIcon(name);
const iconName = isNameValid ? name : 'status-offline'; const iconName = isNameValid ? name : 'status-offline';

View File

@ -5,5 +5,10 @@ import { TUserStatus } from '../../definitions';
export interface IStatus extends TextProps { export interface IStatus extends TextProps {
id: string; id: string;
size: number; 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 Status from './Status';
import { IStatus } from './definition'; import { IStatus } from './definition';
import { useAppSelector } from '../../lib/hooks'; import { useAppSelector } from '../../lib/hooks';
import { getUserPresence } from '../../lib/methods';
const StatusContainer = ({ id, style, size = 32, ...props }: Omit<IStatus, 'status'>): React.ReactElement => { const StatusContainer = ({ id, style, status, size = 32, ...props }: IStatus): React.ReactElement => {
const status = useAppSelector(state => { const connected = useAppSelector(state => state.meteor.connected);
const statusState = useAppSelector(state => {
if (state.settings.Presence_broadcast_disabled) { if (state.settings.Presence_broadcast_disabled) {
return 'disabled'; return 'disabled';
} }
if (state.meteor.connected) { if (state.meteor.connected && state.activeUsers[id]) {
return state.activeUsers[id] && state.activeUsers[id].status; return state.activeUsers[id].status;
}
if (!state.meteor.connected) {
return 'offline';
} }
return 'loading'; 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; 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]; export type TUserStatus = typeof STATUSES[number];

View File

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