[IMPROVE] - migrate RoomItem presentation layer

This commit is contained in:
AlexAlexandre 2021-07-29 15:12:41 -03:00
parent a533e5c827
commit 601a45a194
12 changed files with 209 additions and 207 deletions

View File

@ -1,18 +1,34 @@
import React from 'react';
import { Animated, View, Text } from 'react-native';
import { RectButton } from 'react-native-gesture-handler';
import PropTypes from 'prop-types';
import I18n, { isRTL } from '../../i18n';
import styles, { ACTION_WIDTH, LONG_SWIPE } from './styles';
import { CustomIcon } from '../../lib/Icons';
import { themes } from '../../constants/colors';
interface ILeftActions {
theme: string;
transX: any;
isRead: boolean;
width: number;
onToggleReadPress(): void;
}
interface IRightActions {
theme: string;
transX: any;
favorite: boolean;
width: number;
toggleFav(): void;
onHidePress(): void;
}
const reverse = new Animated.Value(isRTL() ? -1 : 1);
export const LeftActions = React.memo(({
theme, transX, isRead, width, onToggleReadPress
}) => {
}: ILeftActions) => {
const translateX = Animated.multiply(
transX.interpolate({
inputRange: [0, ACTION_WIDTH],
@ -51,7 +67,7 @@ export const LeftActions = React.memo(({
export const RightActions = React.memo(({
transX, favorite, width, toggleFav, onHidePress, theme
}) => {
}: IRightActions) => {
const translateXFav = Animated.multiply(
transX.interpolate({
inputRange: [-width / 2, -ACTION_WIDTH * 2, 0],
@ -113,20 +129,3 @@ export const RightActions = React.memo(({
</View>
);
});
LeftActions.propTypes = {
theme: PropTypes.string,
transX: PropTypes.object,
isRead: PropTypes.bool,
width: PropTypes.number,
onToggleReadPress: PropTypes.func
};
RightActions.propTypes = {
theme: PropTypes.string,
transX: PropTypes.object,
favorite: PropTypes.bool,
width: PropTypes.number,
toggleFav: PropTypes.func,
onHidePress: PropTypes.func
};

View File

@ -1,5 +1,4 @@
import React from 'react';
import PropTypes from 'prop-types';
import { dequal } from 'dequal';
import I18n from '../../i18n';
@ -8,9 +7,27 @@ import Markdown from '../../containers/markdown';
import { themes } from '../../constants/colors';
import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../../lib/encryption/constants';
interface ILastMessage {
theme: string;
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>) => {
if (!showLastMessage) {
return '';
}
@ -45,11 +62,12 @@ const formatMsg = ({
return `${ prefix }${ lastMessage.msg }`;
};
const arePropsEqual = (oldProps, newProps) => dequal(oldProps, newProps);
const arePropsEqual = (oldProps: any, newProps: any) => dequal(oldProps, newProps);
const LastMessage = React.memo(({
lastMessage, type, showLastMessage, username, alert, useRealName, theme
}) => (
}: ILastMessage) => (
// @ts-ignore
<Markdown
msg={formatMsg({
lastMessage, type, showLastMessage, username, useRealName
@ -63,14 +81,4 @@ const LastMessage = React.memo(({
/>
), arePropsEqual);
LastMessage.propTypes = {
theme: PropTypes.string,
lastMessage: PropTypes.object,
type: PropTypes.string,
showLastMessage: PropTypes.bool,
username: PropTypes.string,
useRealName: PropTypes.bool,
alert: PropTypes.bool
};
export default LastMessage;

View File

@ -13,6 +13,53 @@ import Touchable from './Touchable';
import Tag from './Tag';
import I18n from '../../i18n';
interface IRoomItem {
rid: string;
type: string;
prid: string;
name: string;
avatar: string;
showLastMessage: boolean;
username: string;
avatarSize: number;
testID: string;
width: number;
status: string;
useRealName: boolean;
theme: string;
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;
}
const RoomItem = ({
rid,
type,
@ -50,7 +97,7 @@ const RoomItem = ({
hideChannel,
teamMain,
autoJoin
}) => (
}: IRoomItem) => (
<Touchable
onPress={onPress}
onLongPress={onLongPress}
@ -158,49 +205,4 @@ const RoomItem = ({
</Touchable>
);
RoomItem.propTypes = {
rid: PropTypes.string.isRequired,
type: PropTypes.string.isRequired,
prid: PropTypes.string,
name: PropTypes.string.isRequired,
avatar: PropTypes.string.isRequired,
showLastMessage: PropTypes.bool,
username: PropTypes.string,
avatarSize: PropTypes.number,
testID: PropTypes.string,
width: PropTypes.number,
status: PropTypes.string,
useRealName: PropTypes.bool,
theme: PropTypes.string,
isFocused: PropTypes.bool,
isGroupChat: PropTypes.bool,
isRead: PropTypes.bool,
teamMain: PropTypes.bool,
date: PropTypes.string,
accessibilityLabel: PropTypes.string,
lastMessage: PropTypes.object,
favorite: PropTypes.bool,
alert: PropTypes.bool,
hideUnreadStatus: PropTypes.bool,
unread: PropTypes.number,
userMentions: PropTypes.number,
groupMentions: PropTypes.number,
tunread: PropTypes.array,
tunreadUser: PropTypes.array,
tunreadGroup: PropTypes.array,
swipeEnabled: PropTypes.bool,
toggleFav: PropTypes.func,
toggleRead: PropTypes.func,
onPress: PropTypes.func,
onLongPress: PropTypes.func,
hideChannel: PropTypes.func,
autoJoin: PropTypes.bool
};
RoomItem.defaultProps = {
avatarSize: 48,
status: 'offline',
swipeEnabled: true
};
export default RoomItem;

View File

@ -1,13 +1,17 @@
import React from 'react';
import { Text, View } from 'react-native';
import PropTypes from 'prop-types';
import { themes } from '../../constants/colors';
import { useTheme } from '../../theme';
import styles from './styles';
const Tag = React.memo(({ name, testID }) => {
const { theme } = useTheme();
interface ITag {
name: string;
testID?: string;
}
const Tag = React.memo(({ name, testID }: ITag) => {
const { theme }: any = useTheme();
return (
<View style={[styles.tagContainer, { backgroundColor: themes[theme].borderColor }]}>
@ -24,9 +28,4 @@ const Tag = React.memo(({ name, testID }) => {
);
});
Tag.propTypes = {
name: PropTypes.string,
testID: PropTypes.string
};
export default Tag;

View File

@ -1,13 +1,17 @@
import React from 'react';
import { Text } from 'react-native';
import PropTypes from 'prop-types';
import styles from './styles';
import { themes } from '../../constants/colors';
const Title = React.memo(({
name, theme, hideUnreadStatus, alert
}) => (
interface ITitle {
name: string;
theme: string;
hideUnreadStatus: boolean;
alert: boolean;
}
const Title = React.memo(({ name, theme, hideUnreadStatus, alert }: ITitle) => (
<Text
style={[
styles.title,
@ -21,11 +25,4 @@ const Title = React.memo(({
</Text>
));
Title.propTypes = {
name: PropTypes.string,
theme: PropTypes.string,
hideUnreadStatus: PropTypes.bool,
alert: PropTypes.bool
};
export default Title;

View File

@ -15,26 +15,34 @@ import { isRTL } from '../../i18n';
import { themes } from '../../constants/colors';
import { LeftActions, RightActions } from './Actions';
class Touchable extends React.Component {
static propTypes = {
type: PropTypes.string.isRequired,
onPress: PropTypes.func,
onLongPress: PropTypes.func,
testID: PropTypes.string,
width: PropTypes.number,
favorite: PropTypes.bool,
isRead: PropTypes.bool,
rid: PropTypes.string,
toggleFav: PropTypes.func,
toggleRead: PropTypes.func,
hideChannel: PropTypes.func,
children: PropTypes.element,
theme: PropTypes.string,
isFocused: PropTypes.bool,
swipeEnabled: PropTypes.bool
interface ITouchableProps {
children: JSX.Element;
type: string;
onPress(): void;
onLongPress(): void;
testID: string;
width: number;
favorite: boolean;
isRead: boolean;
rid: string;
toggleFav({}?, {}?): void;
toggleRead({}?, {}?): void;
hideChannel({}?, {}?): void;
theme: string;
isFocused: boolean;
swipeEnabled: boolean;
}
constructor(props) {
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 _value: number;
constructor(props: ITouchableProps) {
super(props);
this.dragX = new Animated.Value(0);
this.rowOffSet = new Animated.Value(0);
@ -56,20 +64,20 @@ class Touchable extends React.Component {
this._value = 0;
}
_onHandlerStateChange = ({ nativeEvent }) => {
_onHandlerStateChange = ({ nativeEvent }: any) => {
if (nativeEvent.oldState === State.ACTIVE) {
this._handleRelease(nativeEvent);
}
}
onLongPressHandlerStateChange = ({ nativeEvent }) => {
onLongPressHandlerStateChange = ({ nativeEvent }: any) => {
if (nativeEvent.state === State.ACTIVE) {
this.onLongPress();
}
}
_handleRelease = (nativeEvent) => {
_handleRelease = (nativeEvent: any) => {
const { translationX } = nativeEvent;
const { rowState } = this.state;
this._value += translationX;
@ -152,7 +160,7 @@ class Touchable extends React.Component {
this._animateRow(toValue);
}
_animateRow = (toValue) => {
_animateRow = (toValue: any) => {
this.rowOffSet.setValue(this._value);
this._value = toValue;
this.dragX.setValue(0);

View File

@ -1,18 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import RoomTypeIcon from '../../containers/RoomTypeIcon';
const TypeIcon = React.memo(({
type, prid, status, isGroupChat, teamMain
}) => <RoomTypeIcon type={prid ? 'discussion' : type} isGroupChat={isGroupChat} status={status} teamMain={teamMain} />);
TypeIcon.propTypes = {
type: PropTypes.string,
status: PropTypes.string,
prid: PropTypes.string,
isGroupChat: PropTypes.bool,
teamMain: PropTypes.bool
};
export default TypeIcon;

View File

@ -0,0 +1,17 @@
import React from 'react';
import RoomTypeIcon from '../../containers/RoomTypeIcon';
interface ITypeIcon {
type: string;
status: string;
prid: string;
isGroupChat: boolean;
teamMain: boolean;
theme?: string;
}
const TypeIcon = React.memo(({
type, prid, status, isGroupChat, teamMain
}: ITypeIcon) => <RoomTypeIcon type={prid ? 'discussion' : type} isGroupChat={isGroupChat} status={status} teamMain={teamMain} />);
export default TypeIcon;

View File

@ -1,14 +1,18 @@
import React from 'react';
import { Text } from 'react-native';
import PropTypes from 'prop-types';
import styles from './styles';
import { themes } from '../../constants/colors';
import { capitalize } from '../../utils/room';
const UpdatedAt = React.memo(({
date, theme, hideUnreadStatus, alert
}) => {
interface IUpdatedAt {
date: string;
theme: string;
hideUnreadStatus: boolean;
alert: boolean;
}
const UpdatedAt = React.memo(({ date, theme, hideUnreadStatus, alert }: IUpdatedAt) => {
if (!date) {
return null;
}
@ -38,11 +42,4 @@ const UpdatedAt = React.memo(({
);
});
UpdatedAt.propTypes = {
date: PropTypes.string,
theme: PropTypes.string,
hideUnreadStatus: PropTypes.bool,
alert: PropTypes.bool
};
export default UpdatedAt;

View File

@ -1,11 +1,20 @@
import React from 'react';
import { View } from 'react-native';
import PropTypes from 'prop-types';
import styles from './styles';
import { themes } from '../../constants/colors';
import Avatar from '../../containers/Avatar';
interface IWrapper {
accessibilityLabel: string;
avatar: string;
avatarSize: number;
type: string;
theme: string;
rid: string;
children: JSX.Element;
}
const Wrapper = ({
accessibilityLabel,
avatar,
@ -14,7 +23,7 @@ const Wrapper = ({
theme,
rid,
children
}) => (
}: IWrapper) => (
<View
style={styles.container}
accessibilityLabel={accessibilityLabel}
@ -39,14 +48,4 @@ const Wrapper = ({
</View>
);
Wrapper.propTypes = {
accessibilityLabel: PropTypes.string,
avatar: PropTypes.string,
avatarSize: PropTypes.number,
type: PropTypes.string,
theme: PropTypes.string,
rid: PropTypes.string,
children: PropTypes.element
};
export default Wrapper;

View File

@ -9,6 +9,33 @@ import RoomItem from './RoomItem';
export { ROW_HEIGHT };
interface IRoomItemContainerProps {
item: any;
showLastMessage: boolean;
id: string;
onPress({}?): void;
onLongPress({}?): void;
username: string;
avatarSize: number;
width: number;
status: string;
toggleFav(): void;
toggleRead(): void;
hideChannel(): void;
useRealName: boolean;
getUserPresence: Function;
connected: boolean;
theme: string;
isFocused: boolean;
getRoomTitle: Function;
getRoomAvatar: Function;
getIsGroupChat: Function;
getIsRead: Function;
swipeEnabled: boolean;
autoJoin: boolean;
}
const attrs = [
'width',
'status',
@ -20,45 +47,11 @@ const attrs = [
'autoJoin'
];
class RoomItemContainer extends React.Component {
static propTypes = {
item: PropTypes.object.isRequired,
showLastMessage: PropTypes.bool,
id: PropTypes.string,
onPress: PropTypes.func,
onLongPress: PropTypes.func,
username: PropTypes.string,
avatarSize: PropTypes.number,
width: PropTypes.number,
status: PropTypes.string,
toggleFav: PropTypes.func,
toggleRead: PropTypes.func,
hideChannel: PropTypes.func,
useRealName: PropTypes.bool,
getUserPresence: PropTypes.func,
connected: PropTypes.bool,
theme: PropTypes.string,
isFocused: PropTypes.bool,
getRoomTitle: PropTypes.func,
getRoomAvatar: PropTypes.func,
getIsGroupChat: PropTypes.func,
getIsRead: PropTypes.func,
swipeEnabled: PropTypes.bool,
autoJoin: PropTypes.bool
};
class RoomItemContainer extends React.Component<IRoomItemContainerProps, any> {
private mounted: boolean;
private roomSubscription: any;
static defaultProps = {
avatarSize: 48,
status: 'offline',
getUserPresence: () => {},
getRoomTitle: () => 'title',
getRoomAvatar: () => '',
getIsGroupChat: () => false,
getIsRead: () => false,
swipeEnabled: true
}
constructor(props) {
constructor(props: IRoomItemContainerProps) {
super(props);
this.mounted = false;
this.init();
@ -72,12 +65,12 @@ class RoomItemContainer extends React.Component {
}
}
shouldComponentUpdate(nextProps) {
const { props } = this;
shouldComponentUpdate(nextProps: any) {
const { props }: any = this;
return !attrs.every(key => props[key] === nextProps[key]);
}
componentDidUpdate(prevProps) {
componentDidUpdate(prevProps: any) {
const { connected, getUserPresence, id } = this.props;
if (prevProps.connected !== connected && connected && this.isDirect) {
getUserPresence(id);
@ -96,7 +89,7 @@ class RoomItemContainer extends React.Component {
}
get isDirect() {
const { item: { t }, id } = this.props;
const { item: { t }, id }: any = this.props;
return t === 'd' && id && !this.isGroupChat;
}
@ -165,6 +158,7 @@ class RoomItemContainer extends React.Component {
}
return (
// @ts-ignore
<RoomItem
name={name}
avatar={avatar}
@ -207,7 +201,7 @@ class RoomItemContainer extends React.Component {
}
}
const mapStateToProps = (state, ownProps) => {
const mapStateToProps = (state: any, ownProps: any) => {
let status = 'loading';
const { id, type, visitor = {} } = ownProps;
if (state.meteor.connected) {

View File

@ -7,7 +7,7 @@ export const ACTION_WIDTH = 80;
export const SMALL_SWIPE = ACTION_WIDTH / 2;
export const LONG_SWIPE = ACTION_WIDTH * 3;
export default StyleSheet.create({
export default StyleSheet.create<any>({
flex: {
flex: 1
},