Chore: Properly type Status (#3911)

Co-authored-by: Gleidson Daniel Silva <gleidson10daniel@hotmail.com>
This commit is contained in:
Diego Mello 2022-03-25 17:05:49 -03:00 committed by GitHub
parent 70cb252d1b
commit 902827422b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 74 additions and 72 deletions

View File

@ -7,6 +7,7 @@ import { themes } from '../../constants/colors';
import { MarkdownPreview } from '../markdown';
import RoomTypeIcon from '../RoomTypeIcon';
import { withTheme } from '../../theme';
import { TUserStatus } from '../../definitions';
const HIT_SLOP = {
top: 5,
@ -67,7 +68,7 @@ interface IRoomHeader {
prid: string;
tmid: string;
teamMain: boolean;
status: string;
status: TUserStatus;
theme?: string;
usersTyping: [];
isGroupChat: boolean;

View File

@ -2,7 +2,7 @@ import { dequal } from 'dequal';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { IApplicationState } from '../../definitions';
import { IApplicationState, TUserStatus } from '../../definitions';
import { withDimensions } from '../../dimensions';
import I18n from '../../i18n';
import RoomHeader from './RoomHeader';
@ -15,7 +15,7 @@ interface IRoomHeaderContainerProps {
tmid: string;
teamMain: boolean;
usersTyping: [];
status: string;
status: TUserStatus;
statusText: string;
connecting: boolean;
connected: boolean;
@ -140,7 +140,7 @@ const mapStateToProps = (state: IApplicationState, ownProps: any) => {
connecting: state.meteor.connecting || state.server.loading,
connected: state.meteor.connected,
usersTyping: state.usersTyping,
status,
status: status as TUserStatus,
statusText
};
};

View File

@ -5,6 +5,7 @@ import { CustomIcon } from '../lib/Icons';
import { STATUS_COLORS, themes } from '../constants/colors';
import Status from './Status/Status';
import { withTheme } from '../theme';
import { TUserStatus } from '../definitions';
const styles = StyleSheet.create({
icon: {
@ -17,7 +18,7 @@ interface IRoomTypeIcon {
type: string;
isGroupChat?: boolean;
teamMain?: boolean;
status?: string;
status?: TUserStatus;
size?: number;
style?: ViewStyle;
}
@ -31,9 +32,10 @@ const RoomTypeIcon = React.memo(({ type, isGroupChat, status, style, theme, team
const iconStyle = [styles.icon, { color }, style];
if (type === 'd' && !isGroupChat) {
return (
<Status style={[iconStyle, { color: STATUS_COLORS[status!] ?? STATUS_COLORS.offline }]} size={size} status={status!} />
);
if (!status) {
status = 'offline';
}
return <Status style={[iconStyle, { color: STATUS_COLORS[status] }]} size={size} status={status} />;
}
// TODO: move this to a separate function

View File

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

View File

@ -0,0 +1,9 @@
import { TextProps } from 'react-native';
import { TUserStatus } from '../../definitions';
export interface IStatus extends TextProps {
id: string;
size: number;
status: TUserStatus;
}

View File

@ -1,20 +1,15 @@
import React, { memo } from 'react';
import { connect } from 'react-redux';
import React from 'react';
import { useSelector } from 'react-redux';
import { IApplicationState, TUserStatus } from '../../definitions';
import Status from './Status';
import { IStatus } from './definition';
interface IStatusContainer {
style: any;
size: number;
status: string;
}
const StatusContainer = ({ id, style, size = 32, ...props }: Omit<IStatus, 'status'>): React.ReactElement => {
const status = useSelector((state: IApplicationState) =>
state.meteor.connected ? state.activeUsers[id] && state.activeUsers[id].status : 'loading'
) as TUserStatus;
return <Status size={size} style={style} status={status} {...props} />;
};
const StatusContainer = memo(({ style, size = 32, status }: IStatusContainer) => (
<Status size={size} style={style} status={status} />
));
const mapStateToProps = (state: any, ownProps: any) => ({
status: state.meteor.connected ? state.activeUsers[ownProps.id] && state.activeUsers[ownProps.id].status : 'loading'
});
export default connect(mapStateToProps)(StatusContainer);
export default StatusContainer;

View File

@ -1,7 +1,7 @@
import Model from '@nozbe/watermelondb/Model';
import { IUserEmail, IUserSettings } from './IUser';
import { UserStatus } from './UserStatus';
import { TUserStatus } from './TUserStatus';
export interface ILoggedUser {
id: string;
@ -9,7 +9,7 @@ export interface ILoggedUser {
username: string;
name: string;
language?: string;
status: UserStatus;
status: TUserStatus;
statusText?: string;
customFields?: {
[key: string]: any;

View File

@ -1,6 +1,6 @@
import Model from '@nozbe/watermelondb/Model';
import { UserStatus } from './UserStatus';
import { TUserStatus } from './TUserStatus';
import { IRocketChatRecord } from './IRocketChatRecord';
import { ILoggedUser } from './ILoggedUser';
@ -25,7 +25,7 @@ export interface IPersonalAccessToken extends ILoginToken {
export interface IUserRegistered {
_id: string;
type: string;
status: UserStatus;
status: TUserStatus;
active: boolean;
name: string;
username: string;
@ -133,14 +133,14 @@ export interface IUser extends IRocketChatRecord, Omit<ILoggedUser, 'username' |
name?: string;
services?: IUserServices;
emails?: IUserEmail[];
status: UserStatus;
status: TUserStatus;
statusConnection?: string;
lastLogin?: Date;
avatarOrigin?: string;
avatarETag?: string;
utcOffset?: number;
language?: string;
statusDefault?: UserStatus;
statusDefault?: TUserStatus;
statusText?: string;
oauth?: {
authorizedClients: string[];

View File

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

View File

@ -1,6 +0,0 @@
export enum UserStatus {
ONLINE = 'online',
AWAY = 'away',
OFFLINE = 'offline',
BUSY = 'busy'
}

View File

@ -26,6 +26,7 @@ export * from './ICertificate';
export * from './IUrl';
export * from './ICredentials';
export * from './ISearch';
export * from './TUserStatus';
export interface IBaseScreen<T extends Record<string, object | undefined>, S extends string> {
navigation: StackNavigationProp<T, S>;

View File

@ -73,7 +73,6 @@ export const THEME_PREFERENCES_KEY = 'RC_THEME_PREFERENCES_KEY';
export const CRASH_REPORT_KEY = 'RC_CRASH_REPORT_KEY';
export const ANALYTICS_EVENTS_KEY = 'RC_ANALYTICS_EVENTS_KEY';
export const MIN_ROCKETCHAT_VERSION = '0.70.0';
export const STATUSES = ['offline', 'online', 'away', 'busy'];
const RocketChat = {
TOKEN_KEY,

View File

@ -6,7 +6,6 @@ import { Q } from '@nozbe/watermelondb';
import log from '../../../utils/log';
import { onRolesChanged } from '../../methods/getRoles';
import { UserStatus } from '../../../definitions/UserStatus';
import { setActiveUsers } from '../../../actions/activeUsers';
import protectedFunction from '../../methods/helpers/protectedFunction';
import database from '../../database';
@ -17,8 +16,8 @@ import { store } from '../../auxStore';
import { loginRequest, setLoginServices, setUser } from '../../../actions/login';
import sdk from './sdk';
import I18n from '../../../i18n';
import RocketChat, { MIN_ROCKETCHAT_VERSION, STATUSES } from '../rocketchat';
import { ICredentials, ILoggedUser, IRocketChat } from '../../../definitions';
import RocketChat, { MIN_ROCKETCHAT_VERSION } from '../rocketchat';
import { ICredentials, ILoggedUser, IRocketChat, STATUSES } from '../../../definitions';
import { isIOS } from '../../../utils/deviceInfo';
import { connectRequest, connectSuccess, disconnect as disconnectAction } from '../../../actions/connect';
import { updatePermission } from '../../../actions/permissions';
@ -195,7 +194,7 @@ function connect(
const { user: loggedUser } = store.getState().login;
if (loggedUser && loggedUser.id === id) {
store.dispatch(setUser({ status: STATUSES[status] as UserStatus, statusText }));
store.dispatch(setUser({ status: STATUSES[status], statusText }));
}
} else if (/updateAvatar/.test(eventName)) {
const { username, etag } = ddpMessage.fields.args[0];

View File

@ -12,6 +12,7 @@ import Touchable from './Touchable';
import Tag from './Tag';
import I18n from '../../i18n';
import { DisplayMode } from '../../constants/constantDisplayMode';
import { TUserStatus } from '../../definitions';
interface IRoomItem {
rid: string;
@ -24,7 +25,7 @@ interface IRoomItem {
avatarSize: number;
testID: string;
width: number;
status: string;
status: TUserStatus;
useRealName: boolean;
theme: string;
isFocused: boolean;

View File

@ -1,10 +1,11 @@
import React from 'react';
import { TUserStatus } from '../../definitions';
import RoomTypeIcon from '../../containers/RoomTypeIcon';
interface ITypeIcon {
type: string;
status: string;
status: TUserStatus;
prid: string;
isGroupChat: boolean;
teamMain: boolean;

View File

@ -5,6 +5,7 @@ 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';
export { ROW_HEIGHT, ROW_HEIGHT_CONDENSED };
interface IRoomItemContainerProps {
@ -16,7 +17,7 @@ interface IRoomItemContainerProps {
username: string;
avatarSize: number;
width: number;
status: string;
status: TUserStatus;
toggleFav(): void;
toggleRead(): void;
hideChannel(): void;
@ -53,7 +54,7 @@ class RoomItemContainer extends React.Component<IRoomItemContainerProps, any> {
private roomSubscription: any;
static defaultProps = {
static defaultProps: Partial<IRoomItemContainerProps> = {
avatarSize: 48,
status: 'offline',
getUserPresence: () => {},
@ -233,7 +234,7 @@ const mapStateToProps = (state: any, ownProps: any) => {
}
return {
connected: state.meteor.connected,
status
status: status as TUserStatus
};
};

View File

@ -1,5 +1,4 @@
import { clearActiveUsers, setActiveUsers } from '../actions/activeUsers';
import { UserStatus } from '../definitions/UserStatus';
import { IActiveUsers, initialState } from './activeUsers';
import { mockedStore } from './mockedStore';
@ -9,7 +8,7 @@ describe('test reducer', () => {
expect(state).toEqual(initialState);
});
it('should return modified store after action', () => {
const activeUsers: IActiveUsers = { any: { status: UserStatus.ONLINE, statusText: 'any' } };
const activeUsers: IActiveUsers = { any: { status: 'online', statusText: 'any' } };
mockedStore.dispatch(setActiveUsers(activeUsers));
const state = mockedStore.getState().activeUsers;
expect(state).toEqual({ ...activeUsers });

View File

@ -1,9 +1,8 @@
import { ACTIVE_USERS } from '../actions/actionsTypes';
import { TApplicationActions } from '../definitions';
import { UserStatus } from '../definitions/UserStatus';
import { TApplicationActions, TUserStatus } from '../definitions';
export interface IActiveUser {
status: UserStatus;
status: TUserStatus;
statusText: string;
}

View File

@ -1,3 +1,4 @@
import { TUserStatus } from '../definitions';
import {
clearUser,
loginFailure,
@ -8,7 +9,6 @@ import {
setLoginServices,
setUser
} from '../actions/login';
import { UserStatus } from '../definitions/UserStatus';
import { initialState } from './login';
import { mockedStore } from './mockedStore';
@ -49,7 +49,7 @@ describe('test selectedUsers reducer', () => {
isFromWebView: false,
showMessageInMainThread: false,
enableMessageParserEarlyAdoption: false,
status: UserStatus.ONLINE,
status: 'online' as TUserStatus,
statusText: 'online'
};
mockedStore.dispatch(loginSuccess(user));

View File

@ -1,7 +1,6 @@
import { UserStatus } from '../definitions/UserStatus';
import * as types from '../actions/actionsTypes';
import { TActionsLogin } from '../actions/login';
import { IUser } from '../definitions';
import { IUser, TUserStatus } from '../definitions';
export interface IUserLogin {
id: string;
@ -9,7 +8,7 @@ export interface IUserLogin {
username: string;
name: string;
language?: string;
status: UserStatus;
status: TUserStatus;
statusText: string;
roles: string[];
avatarETag?: string;

View File

@ -19,6 +19,7 @@ import Navigation from '../../lib/Navigation';
import SidebarItem from './SidebarItem';
import styles from './styles';
import { DrawerParamList } from '../../stacks/types';
import { TUserStatus } from '../../definitions';
interface ISeparatorProps {
theme: string;
@ -40,7 +41,7 @@ interface ISidebarProps {
Site_Name: string;
user: {
statusText: string;
status: string;
status: TUserStatus;
username: string;
name: string;
roles: string[];

View File

@ -2,7 +2,6 @@ import React from 'react';
import { FlatList, StyleSheet } from 'react-native';
import { connect } from 'react-redux';
import { UserStatus } from '../definitions/UserStatus';
import { setUser } from '../actions/login';
import * as HeaderButton from '../containers/HeaderButton';
import * as List from '../containers/List';
@ -11,7 +10,7 @@ import SafeAreaView from '../containers/SafeAreaView';
import Status from '../containers/Status/Status';
import TextInput from '../containers/TextInput';
import { LISTENER } from '../containers/Toast';
import { IApplicationState, IBaseScreen, IUser } from '../definitions';
import { IApplicationState, IBaseScreen, IUser, TUserStatus } from '../definitions';
import I18n from '../i18n';
import RocketChat from '../lib/rocketchat';
import { getUserSelector } from '../selectors/login';
@ -20,7 +19,12 @@ import EventEmitter from '../utils/events';
import { showErrorAlert } from '../utils/info';
import log, { events, logEvent } from '../utils/log';
const STATUS = [
interface IStatus {
id: TUserStatus;
name: string;
}
const STATUS: IStatus[] = [
{
id: 'online',
name: 'Online'
@ -135,7 +139,7 @@ class StatusView extends React.Component<IStatusViewProps, IStatusViewState> {
value={statusText}
containerStyle={styles.inputContainer}
onChangeText={text => this.setState({ statusText: text })}
left={<Status testID={`status-view-current-${user.status}`} style={styles.inputLeft} status={user.status!} size={24} />}
left={<Status testID={`status-view-current-${user.status}`} style={styles.inputLeft} status={user.status} size={24} />}
inputStyle={styles.inputStyle}
placeholder={I18n.t('What_are_you_doing_right_now')}
testID='status-view-input'
@ -145,7 +149,7 @@ class StatusView extends React.Component<IStatusViewProps, IStatusViewState> {
);
};
renderItem = ({ item }: { item: { id: string; name: string } }) => {
renderItem = ({ item }: { item: IStatus }) => {
const { statusText } = this.state;
const { user, dispatch } = this.props;
const { id, name } = item;
@ -159,7 +163,7 @@ class StatusView extends React.Component<IStatusViewProps, IStatusViewState> {
try {
const result = await RocketChat.setUserStatus(item.id, statusText);
if (result.success) {
dispatch(setUser({ status: item.id as UserStatus }));
dispatch(setUser({ status: item.id }));
}
} catch (e: any) {
showErrorAlert(I18n.t(e.data.errorType));

File diff suppressed because one or more lines are too long