Chore: Migrate containers/Avatar to hooks (#4139)
* Migrate containers/Avatar to hooks * Migrate to `useSelector` hook and `useRef` * Change user object prop to primitive type * fix re-render and update snapshot * fix lint * update pods Co-authored-by: GleidsonDaniel <gleidson10daniel@hotmail.com>
This commit is contained in:
parent
614d9afe65
commit
748e87acf3
|
@ -8,7 +8,6 @@ import { getAvatarURL } from '../../lib/methods/helpers/getAvatarUrl';
|
|||
import { SubscriptionType } from '../../definitions';
|
||||
import Emoji from '../markdown/Emoji';
|
||||
import { IAvatar } from './interfaces';
|
||||
import { useTheme } from '../../theme';
|
||||
|
||||
const Avatar = React.memo(
|
||||
({
|
||||
|
@ -16,7 +15,8 @@ const Avatar = React.memo(
|
|||
style,
|
||||
avatar,
|
||||
children,
|
||||
user,
|
||||
userId,
|
||||
token,
|
||||
onPress,
|
||||
emoji,
|
||||
getCustomEmoji,
|
||||
|
@ -31,8 +31,6 @@ const Avatar = React.memo(
|
|||
type = SubscriptionType.DIRECT,
|
||||
externalProviderUrl
|
||||
}: IAvatar) => {
|
||||
const { theme } = useTheme();
|
||||
|
||||
if ((!text && !avatar && !emoji && !rid) || !server) {
|
||||
return null;
|
||||
}
|
||||
|
@ -46,14 +44,7 @@ const Avatar = React.memo(
|
|||
let image;
|
||||
if (emoji) {
|
||||
image = (
|
||||
<Emoji
|
||||
theme={theme}
|
||||
baseUrl={server}
|
||||
getCustomEmoji={getCustomEmoji}
|
||||
isMessageContainsOnlyEmoji
|
||||
literal={emoji}
|
||||
style={avatarStyle}
|
||||
/>
|
||||
<Emoji baseUrl={server} getCustomEmoji={getCustomEmoji} isMessageContainsOnlyEmoji literal={emoji} style={avatarStyle} />
|
||||
);
|
||||
} else {
|
||||
let uri = avatar;
|
||||
|
@ -62,7 +53,8 @@ const Avatar = React.memo(
|
|||
type,
|
||||
text,
|
||||
size,
|
||||
user,
|
||||
userId,
|
||||
token,
|
||||
avatar,
|
||||
server,
|
||||
avatarETag,
|
||||
|
|
|
@ -1,113 +1,112 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { shallowEqual, useSelector } from 'react-redux';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
|
||||
import { IApplicationState, TSubscriptionModel, TUserModel } from '../../definitions';
|
||||
import database from '../../lib/database';
|
||||
import { getUserSelector } from '../../selectors/login';
|
||||
import { IApplicationState, TSubscriptionModel, TUserModel } from '../../definitions';
|
||||
import Avatar from './Avatar';
|
||||
import { IAvatar } from './interfaces';
|
||||
|
||||
class AvatarContainer extends React.Component<IAvatar, any> {
|
||||
private subscription?: Subscription;
|
||||
const AvatarContainer = ({
|
||||
style,
|
||||
text = '',
|
||||
avatar,
|
||||
emoji,
|
||||
size,
|
||||
borderRadius,
|
||||
type,
|
||||
children,
|
||||
onPress,
|
||||
getCustomEmoji,
|
||||
isStatic,
|
||||
rid
|
||||
}: IAvatar): React.ReactElement => {
|
||||
const subscription = useRef<Subscription>();
|
||||
const [avatarETag, setAvatarETag] = useState<string | undefined>('');
|
||||
|
||||
static defaultProps = {
|
||||
text: '',
|
||||
type: 'd'
|
||||
};
|
||||
const isDirect = () => type === 'd';
|
||||
|
||||
constructor(props: IAvatar) {
|
||||
super(props);
|
||||
this.state = { avatarETag: '' };
|
||||
this.init();
|
||||
}
|
||||
const server = useSelector((state: IApplicationState) => state.share.server.server || state.server.server);
|
||||
const serverVersion = useSelector((state: IApplicationState) => state.share.server.version || state.server.version);
|
||||
const { id, token } = useSelector(
|
||||
(state: IApplicationState) => ({
|
||||
id: getUserSelector(state).id,
|
||||
token: getUserSelector(state).token
|
||||
}),
|
||||
shallowEqual
|
||||
);
|
||||
|
||||
componentDidUpdate(prevProps: IAvatar) {
|
||||
const { text, type } = this.props;
|
||||
if (prevProps.text !== text || prevProps.type !== type) {
|
||||
this.init();
|
||||
}
|
||||
}
|
||||
const externalProviderUrl = useSelector(
|
||||
(state: IApplicationState) => state.settings.Accounts_AvatarExternalProviderUrl as string
|
||||
);
|
||||
const blockUnauthenticatedAccess = useSelector(
|
||||
(state: IApplicationState) =>
|
||||
(state.share.settings?.Accounts_AvatarBlockUnauthenticatedAccess as boolean) ??
|
||||
state.settings.Accounts_AvatarBlockUnauthenticatedAccess ??
|
||||
true
|
||||
);
|
||||
|
||||
shouldComponentUpdate(nextProps: IAvatar, nextState: { avatarETag: string }) {
|
||||
const { avatarETag } = this.state;
|
||||
const { text, type, size, externalProviderUrl } = this.props;
|
||||
if (nextProps.externalProviderUrl !== externalProviderUrl) {
|
||||
return true;
|
||||
}
|
||||
if (nextState.avatarETag !== avatarETag) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.text !== text) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.type !== type) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.size !== size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.subscription?.unsubscribe) {
|
||||
this.subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
get isDirect() {
|
||||
const { type } = this.props;
|
||||
return type === 'd';
|
||||
}
|
||||
|
||||
init = async () => {
|
||||
const init = async () => {
|
||||
const db = database.active;
|
||||
const usersCollection = db.get('users');
|
||||
const subsCollection = db.get('subscriptions');
|
||||
|
||||
let record;
|
||||
try {
|
||||
if (this.isDirect) {
|
||||
const { text } = this.props;
|
||||
if (isDirect()) {
|
||||
const [user] = await usersCollection.query(Q.where('username', text)).fetch();
|
||||
record = user;
|
||||
} else {
|
||||
const { rid } = this.props;
|
||||
if (rid) {
|
||||
} else if (rid) {
|
||||
record = await subsCollection.find(rid);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Record not found
|
||||
}
|
||||
|
||||
if (record) {
|
||||
const observable = record.observe() as Observable<TSubscriptionModel | TUserModel>;
|
||||
this.subscription = observable.subscribe(r => {
|
||||
const { avatarETag } = r;
|
||||
this.setState({ avatarETag });
|
||||
subscription.current = observable.subscribe(r => {
|
||||
setAvatarETag(r.avatarETag);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { avatarETag } = this.state;
|
||||
const { serverVersion } = this.props;
|
||||
return <Avatar {...this.props} avatarETag={avatarETag} serverVersion={serverVersion} />;
|
||||
useEffect(() => {
|
||||
if (!avatarETag) {
|
||||
init();
|
||||
}
|
||||
return () => {
|
||||
if (subscription?.current?.unsubscribe) {
|
||||
subscription.current.unsubscribe();
|
||||
}
|
||||
};
|
||||
}, [text, type, size, avatarETag, externalProviderUrl]);
|
||||
|
||||
const mapStateToProps = (state: IApplicationState) => ({
|
||||
user: getUserSelector(state),
|
||||
server: state.share.server.server || state.server.server,
|
||||
serverVersion: state.share.server.version || state.server.version,
|
||||
blockUnauthenticatedAccess:
|
||||
(state.share.settings?.Accounts_AvatarBlockUnauthenticatedAccess as boolean) ??
|
||||
state.settings.Accounts_AvatarBlockUnauthenticatedAccess ??
|
||||
true,
|
||||
externalProviderUrl: state.settings.Accounts_AvatarExternalProviderUrl as string
|
||||
});
|
||||
export default connect(mapStateToProps)(AvatarContainer);
|
||||
return (
|
||||
<Avatar
|
||||
server={server}
|
||||
style={style}
|
||||
text={text}
|
||||
avatar={avatar}
|
||||
emoji={emoji}
|
||||
size={size}
|
||||
borderRadius={borderRadius}
|
||||
type={type}
|
||||
children={children}
|
||||
userId={id}
|
||||
token={token}
|
||||
onPress={onPress}
|
||||
getCustomEmoji={getCustomEmoji}
|
||||
isStatic={isStatic}
|
||||
rid={rid}
|
||||
blockUnauthenticatedAccess={blockUnauthenticatedAccess}
|
||||
externalProviderUrl={externalProviderUrl}
|
||||
avatarETag={avatarETag}
|
||||
serverVersion={serverVersion}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default AvatarContainer;
|
||||
|
|
|
@ -5,23 +5,21 @@ import { TGetCustomEmoji } from '../../definitions/IEmoji';
|
|||
export interface IAvatar {
|
||||
server?: string;
|
||||
style?: any;
|
||||
text: string;
|
||||
text?: string;
|
||||
avatar?: string;
|
||||
emoji?: string;
|
||||
size?: number;
|
||||
borderRadius?: number;
|
||||
type?: string;
|
||||
children?: React.ReactElement | null;
|
||||
user?: {
|
||||
id?: string;
|
||||
userId?: string;
|
||||
token?: string;
|
||||
};
|
||||
onPress?: () => void;
|
||||
getCustomEmoji?: TGetCustomEmoji;
|
||||
avatarETag?: string;
|
||||
isStatic?: boolean | string;
|
||||
rid?: string;
|
||||
blockUnauthenticatedAccess?: boolean;
|
||||
serverVersion: string | null;
|
||||
serverVersion?: string | null;
|
||||
externalProviderUrl?: string;
|
||||
}
|
||||
|
|
|
@ -3,9 +3,8 @@ import { Text } from 'react-native';
|
|||
|
||||
import shortnameToUnicode from '../../lib/methods/helpers/shortnameToUnicode';
|
||||
import CustomEmoji from '../EmojiPicker/CustomEmoji';
|
||||
import { themes } from '../../lib/constants';
|
||||
import styles from './styles';
|
||||
import { TSupportedThemes } from '../../theme';
|
||||
import { useTheme } from '../../theme';
|
||||
|
||||
interface IEmoji {
|
||||
literal: string;
|
||||
|
@ -14,13 +13,13 @@ interface IEmoji {
|
|||
baseUrl: string;
|
||||
customEmojis?: any;
|
||||
style?: object;
|
||||
theme: TSupportedThemes;
|
||||
onEmojiSelected?: Function;
|
||||
tabEmojiStyle?: object;
|
||||
}
|
||||
|
||||
const Emoji = React.memo(
|
||||
({ literal, isMessageContainsOnlyEmoji, getCustomEmoji, baseUrl, customEmojis = true, style = {}, theme }: IEmoji) => {
|
||||
({ literal, isMessageContainsOnlyEmoji, getCustomEmoji, baseUrl, customEmojis = true, style = {} }: IEmoji) => {
|
||||
const { colors } = useTheme();
|
||||
const emojiUnicode = shortnameToUnicode(literal);
|
||||
const emoji: any = getCustomEmoji && getCustomEmoji(literal.replace(/:/g, ''));
|
||||
if (emoji && customEmojis) {
|
||||
|
@ -33,7 +32,7 @@ const Emoji = React.memo(
|
|||
);
|
||||
}
|
||||
return (
|
||||
<Text style={[{ color: themes[theme].bodyText }, isMessageContainsOnlyEmoji ? styles.textBig : styles.text, style]}>
|
||||
<Text style={[{ color: colors.bodyText }, isMessageContainsOnlyEmoji ? styles.textBig : styles.text, style]}>
|
||||
{emojiUnicode}
|
||||
</Text>
|
||||
);
|
||||
|
|
|
@ -233,7 +233,7 @@ class Markdown extends PureComponent<IMarkdownProps, any> {
|
|||
};
|
||||
|
||||
renderEmoji = ({ literal }: TLiteral) => {
|
||||
const { getCustomEmoji, baseUrl = '', customEmojis, style, theme } = this.props;
|
||||
const { getCustomEmoji, baseUrl = '', customEmojis, style } = this.props;
|
||||
return (
|
||||
<MarkdownEmoji
|
||||
literal={literal}
|
||||
|
@ -242,7 +242,6 @@ class Markdown extends PureComponent<IMarkdownProps, any> {
|
|||
baseUrl={baseUrl}
|
||||
customEmojis={customEmojis}
|
||||
style={style}
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -6,9 +6,10 @@ const formatUrl = (url: string, size: number, query?: string) => `${url}?format=
|
|||
|
||||
export const getAvatarURL = ({
|
||||
type,
|
||||
text,
|
||||
text = '',
|
||||
size = 25,
|
||||
user = {},
|
||||
userId,
|
||||
token,
|
||||
avatar,
|
||||
server,
|
||||
avatarETag,
|
||||
|
@ -30,10 +31,9 @@ export const getAvatarURL = ({
|
|||
room = `@${text}`;
|
||||
}
|
||||
|
||||
const { id, token } = user;
|
||||
let query = '';
|
||||
if (id && token && blockUnauthenticatedAccess) {
|
||||
query += `&rc_token=${token}&rc_uid=${id}`;
|
||||
if (userId && token && blockUnauthenticatedAccess) {
|
||||
query += `&rc_token=${token}&rc_uid=${userId}`;
|
||||
}
|
||||
if (avatarETag) {
|
||||
query += `&etag=${avatarETag}`;
|
||||
|
|
|
@ -36,7 +36,8 @@ const SelectChannel = ({
|
|||
getAvatarURL({
|
||||
text: getRoomAvatar(item),
|
||||
type: item.t,
|
||||
user: { id: userId, token },
|
||||
userId,
|
||||
token,
|
||||
server,
|
||||
avatarETag: item.avatarETag,
|
||||
rid: item.rid,
|
||||
|
|
|
@ -40,7 +40,8 @@ const SelectUsers = ({
|
|||
getAvatarURL({
|
||||
text: getRoomAvatar(item),
|
||||
type: SubscriptionType.DIRECT,
|
||||
user: { id: userId, token },
|
||||
userId,
|
||||
token,
|
||||
server,
|
||||
avatarETag: item.avatarETag,
|
||||
blockUnauthenticatedAccess,
|
||||
|
|
Loading…
Reference in New Issue