Chore: Evaluate RoomView - TypeScript (#4134)
* Chore: Evaluate RoomView - TypeScript * fix messagebox and list refs * fix the refs * refactor other refs * remove any from privates * storyshot tweak
This commit is contained in:
parent
cb1dabbc16
commit
a84d4e9534
|
@ -7,8 +7,8 @@ export type TActionSheetOptionsItem = { title: string; icon: TIconsName; onPress
|
|||
|
||||
export type TActionSheetOptions = {
|
||||
options: TActionSheetOptionsItem[];
|
||||
headerHeight: number;
|
||||
customHeader: React.ReactElement | null;
|
||||
headerHeight?: number;
|
||||
customHeader?: React.ReactElement | null;
|
||||
hasCancel?: boolean;
|
||||
};
|
||||
interface IActionSheetProvider {
|
||||
|
|
|
@ -19,7 +19,7 @@ import { IApplicationState, ILoggedUser, TAnyMessageModel, TSubscriptionModel }
|
|||
import { getPermalinkMessage, hasPermission } from '../../lib/methods';
|
||||
import { Services } from '../../lib/services';
|
||||
|
||||
export interface IMessageActions {
|
||||
export interface IMessageActionsProps {
|
||||
room: TSubscriptionModel;
|
||||
tmid?: string;
|
||||
user: Pick<ILoggedUser, 'id'>;
|
||||
|
@ -43,8 +43,12 @@ export interface IMessageActions {
|
|||
pinMessagePermission?: string[];
|
||||
}
|
||||
|
||||
export interface IMessageActions {
|
||||
showMessageActions: (message: TAnyMessageModel) => Promise<void>;
|
||||
}
|
||||
|
||||
const MessageActions = React.memo(
|
||||
forwardRef(
|
||||
forwardRef<IMessageActions, IMessageActionsProps>(
|
||||
(
|
||||
{
|
||||
room,
|
||||
|
@ -68,7 +72,7 @@ const MessageActions = React.memo(
|
|||
deleteMessagePermission,
|
||||
forceDeleteMessagePermission,
|
||||
pinMessagePermission
|
||||
}: IMessageActions,
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
let permissions = {
|
||||
|
|
|
@ -128,7 +128,7 @@ interface IMessageBoxState {
|
|||
}
|
||||
|
||||
class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
||||
private text: string;
|
||||
public text: string;
|
||||
|
||||
private selection: { start: number; end: number };
|
||||
|
||||
|
@ -1182,4 +1182,6 @@ const dispatchToProps = {
|
|||
typing: (rid: any, status: any) => userTypingAction(rid, status)
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, dispatchToProps, null, { forwardRef: true })(withActionSheet(MessageBox)) as any;
|
||||
export type MessageBoxType = MessageBox;
|
||||
|
||||
export default connect(mapStateToProps, dispatchToProps, null, { forwardRef: true })(withActionSheet(MessageBox));
|
||||
|
|
|
@ -9,9 +9,12 @@ import log from '../utils/log';
|
|||
import { TMessageModel } from '../definitions';
|
||||
import { resendMessage } from '../lib/methods';
|
||||
|
||||
const MessageErrorActions = forwardRef(({ tmid }: { tmid: string }, ref) => {
|
||||
// TODO - remove this any after merge ActionSheet evaluate
|
||||
const { showActionSheet }: any = useActionSheet();
|
||||
export interface IMessageErrorActions {
|
||||
showMessageErrorActions: (message: TMessageModel) => void;
|
||||
}
|
||||
|
||||
const MessageErrorActions = forwardRef<IMessageErrorActions, { tmid?: string }>(({ tmid }, ref) => {
|
||||
const { showActionSheet } = useActionSheet();
|
||||
|
||||
const handleResend = protectedFunction(async (message: TMessageModel) => {
|
||||
await resendMessage(message, tmid);
|
||||
|
|
|
@ -50,8 +50,12 @@ export interface IJoinCodeProps {
|
|||
theme: TSupportedThemes;
|
||||
}
|
||||
|
||||
export interface IJoinCode {
|
||||
show: () => void;
|
||||
}
|
||||
|
||||
const JoinCode = React.memo(
|
||||
forwardRef(({ rid, t, onJoin, isMasterDetail, theme }: IJoinCodeProps, ref) => {
|
||||
forwardRef<IJoinCode, IJoinCodeProps>(({ rid, t, onJoin, isMasterDetail, theme }, ref) => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [error, setError] = useState(false);
|
||||
const [code, setCode] = useState('');
|
||||
|
@ -125,4 +129,5 @@ const JoinCode = React.memo(
|
|||
const mapStateToProps = (state: IApplicationState) => ({
|
||||
isMasterDetail: state.app.isMasterDetail
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, null, null, { forwardRef: true })(JoinCode);
|
||||
|
|
|
@ -17,8 +17,10 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
export type TListRef = React.RefObject<FlatList & { getNode: () => FlatList }>;
|
||||
|
||||
export interface IListProps extends FlatListProps<any> {
|
||||
listRef: any;
|
||||
listRef: TListRef;
|
||||
}
|
||||
|
||||
const List = ({ listRef, ...props }: IListProps) => (
|
||||
|
|
|
@ -16,7 +16,7 @@ import debounce from '../../../utils/debounce';
|
|||
import { animateNextTransition } from '../../../utils/layoutAnimation';
|
||||
import log from '../../../utils/log';
|
||||
import EmptyRoom from '../EmptyRoom';
|
||||
import List, { IListProps } from './List';
|
||||
import List, { IListProps, TListRef } from './List';
|
||||
import NavBottomFAB from './NavBottomFAB';
|
||||
import { loadMissedMessages, loadThreadMessages } from '../../../lib/methods';
|
||||
import { Services } from '../../../lib/services';
|
||||
|
@ -43,7 +43,7 @@ export interface IListContainerProps {
|
|||
tmid?: string;
|
||||
theme: TSupportedThemes;
|
||||
loading: boolean;
|
||||
listRef: React.RefObject<IListProps>;
|
||||
listRef: TListRef;
|
||||
hideSystemMessages?: string[];
|
||||
tunread?: string[];
|
||||
ignored?: string[];
|
||||
|
@ -272,8 +272,7 @@ class ListContainer extends React.Component<IListContainerProps, IListContainerS
|
|||
|
||||
handleScrollToIndexFailed: FlatListProps<any>['onScrollToIndexFailed'] = params => {
|
||||
const { listRef } = this.props;
|
||||
// @ts-ignore
|
||||
listRef.current.getNode().scrollToIndex({ index: params.highestMeasuredFrameIndex, animated: false });
|
||||
listRef.current?.getNode().scrollToIndex({ index: params.highestMeasuredFrameIndex, animated: false });
|
||||
};
|
||||
|
||||
jumpToMessage = (messageId: string) =>
|
||||
|
@ -283,8 +282,7 @@ class ListContainer extends React.Component<IListContainerProps, IListContainerS
|
|||
const { listRef } = this.props;
|
||||
const index = messages.findIndex(item => item.id === messageId);
|
||||
if (index > -1) {
|
||||
// @ts-ignore
|
||||
listRef.current.getNode().scrollToIndex({ index, viewPosition: 0.5, viewOffset: 100 });
|
||||
listRef.current?.getNode().scrollToIndex({ index, viewPosition: 0.5, viewOffset: 100 });
|
||||
await new Promise(res => setTimeout(res, 300));
|
||||
if (!this.viewableItems?.map(vi => vi.key).includes(messageId)) {
|
||||
if (!this.jumping) {
|
||||
|
@ -300,8 +298,7 @@ class ListContainer extends React.Component<IListContainerProps, IListContainerS
|
|||
}, 10000);
|
||||
await setTimeout(() => resolve(), 300);
|
||||
} else {
|
||||
// @ts-ignore
|
||||
listRef.current.getNode().scrollToIndex({ index: messages.length - 1, animated: false });
|
||||
listRef.current?.getNode().scrollToIndex({ index: messages.length - 1, animated: false });
|
||||
if (!this.jumping) {
|
||||
return resolve();
|
||||
}
|
||||
|
@ -316,8 +313,7 @@ class ListContainer extends React.Component<IListContainerProps, IListContainerS
|
|||
|
||||
jumpToBottom = () => {
|
||||
const { listRef } = this.props;
|
||||
// @ts-ignore
|
||||
listRef.current.getNode().scrollToOffset({ offset: -100 });
|
||||
listRef.current?.getNode().scrollToOffset({ offset: -100 });
|
||||
};
|
||||
|
||||
renderFooter = () => {
|
||||
|
@ -367,4 +363,6 @@ class ListContainer extends React.Component<IListContainerProps, IListContainerS
|
|||
}
|
||||
}
|
||||
|
||||
export type ListContainerType = ListContainer;
|
||||
|
||||
export default ListContainer;
|
||||
|
|
|
@ -15,8 +15,8 @@ import { replyBroadcast } from '../../actions/messages';
|
|||
import database from '../../lib/database';
|
||||
import Message from '../../containers/message';
|
||||
import MessageActions, { IMessageActions } from '../../containers/MessageActions';
|
||||
import MessageErrorActions from '../../containers/MessageErrorActions';
|
||||
import MessageBox, { IMessageBoxProps } from '../../containers/MessageBox';
|
||||
import MessageErrorActions, { IMessageErrorActions } from '../../containers/MessageErrorActions';
|
||||
import MessageBox, { MessageBoxType } from '../../containers/MessageBox';
|
||||
import log, { events, logEvent } from '../../utils/log';
|
||||
import EventEmitter from '../../utils/events';
|
||||
import I18n from '../../i18n';
|
||||
|
@ -58,10 +58,10 @@ import Separator from './Separator';
|
|||
import RightButtons from './RightButtons';
|
||||
import LeftButtons from './LeftButtons';
|
||||
import styles from './styles';
|
||||
import JoinCode, { IJoinCodeProps } from './JoinCode';
|
||||
import JoinCode, { IJoinCode } from './JoinCode';
|
||||
import UploadProgress from './UploadProgress';
|
||||
import ReactionPicker from './ReactionPicker';
|
||||
import List, { IListContainerProps, IListProps } from './List';
|
||||
import List, { ListContainerType } from './List';
|
||||
import { ChatsStackParamList } from '../../stacks/types';
|
||||
import {
|
||||
IApplicationState,
|
||||
|
@ -80,6 +80,8 @@ import {
|
|||
} from '../../definitions';
|
||||
import { ICustomEmojis } from '../../reducers/customEmojis';
|
||||
import { E2E_MESSAGE_TYPE, E2E_STATUS, MESSAGE_TYPE_ANY_LOAD, MessageTypeLoad, themes } from '../../lib/constants';
|
||||
import { TListRef } from './List/List';
|
||||
import { ModalStackParamList } from '../../stacks/MasterDetailStack/types';
|
||||
import {
|
||||
callJitsi,
|
||||
canAutoTranslate as canAutoTranslateMethod,
|
||||
|
@ -94,6 +96,8 @@ import {
|
|||
} from '../../lib/methods';
|
||||
import { Services } from '../../lib/services';
|
||||
|
||||
type TStateAttrsUpdate = keyof IRoomViewState;
|
||||
|
||||
const stateAttrsUpdate = [
|
||||
'joined',
|
||||
'lastOpen',
|
||||
|
@ -107,7 +111,10 @@ const stateAttrsUpdate = [
|
|||
'readOnly',
|
||||
'member',
|
||||
'showingBlockingLoader'
|
||||
];
|
||||
] as TStateAttrsUpdate[];
|
||||
|
||||
type TRoomUpdate = keyof TSubscriptionModel;
|
||||
|
||||
const roomAttrsUpdate = [
|
||||
'f',
|
||||
'ro',
|
||||
|
@ -130,7 +137,7 @@ const roomAttrsUpdate = [
|
|||
'teamMain',
|
||||
'teamId',
|
||||
'onHold'
|
||||
] as const;
|
||||
] as TRoomUpdate[];
|
||||
|
||||
interface IRoomViewProps extends IBaseScreen<ChatsStackParamList, 'RoomView'> {
|
||||
user: Pick<ILoggedUser, 'id' | 'username' | 'token' | 'showMessageInMainThread'>;
|
||||
|
@ -151,14 +158,12 @@ interface IRoomViewProps extends IBaseScreen<ChatsStackParamList, 'RoomView'> {
|
|||
insets: EdgeInsets;
|
||||
}
|
||||
|
||||
type TRoomUpdate = typeof roomAttrsUpdate[number];
|
||||
|
||||
interface IRoomViewState {
|
||||
[key: string]: any;
|
||||
joined: boolean;
|
||||
room: TSubscriptionModel | { rid: string; t: string; name?: string; fname?: string; prid?: string; joinCodeRequired?: boolean };
|
||||
roomUpdate: {
|
||||
[K in TRoomUpdate]?: any; // TODO: get type from TSubscriptionModel
|
||||
[K in TRoomUpdate]?: any;
|
||||
};
|
||||
member: any;
|
||||
lastOpen: Date | null;
|
||||
|
@ -182,23 +187,27 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
private tmid?: string;
|
||||
private jumpToMessageId?: string;
|
||||
private jumpToThreadId?: string;
|
||||
// TODO: review these refs
|
||||
private messagebox: React.RefObject<IMessageBoxProps>;
|
||||
private list: React.RefObject<IListContainerProps>;
|
||||
private joinCode: React.RefObject<IJoinCodeProps>;
|
||||
private flatList: React.RefObject<IListProps>;
|
||||
private messagebox: React.RefObject<MessageBoxType>;
|
||||
private list: React.RefObject<ListContainerType>;
|
||||
private joinCode: React.RefObject<IJoinCode>;
|
||||
private flatList: TListRef;
|
||||
private mounted: boolean;
|
||||
private sub?: any;
|
||||
private offset = 0;
|
||||
private didMountInteraction: any;
|
||||
private subSubscription?: Subscription;
|
||||
private queryUnreads?: Subscription;
|
||||
private retryInit = 0;
|
||||
private retryInitTimeout?: number;
|
||||
private retryFindCount = 0;
|
||||
private retryFindTimeout?: number;
|
||||
private messageErrorActions?: React.RefObject<any>; // TODO: type me
|
||||
private messageActions?: React.RefObject<IMessageActions>;
|
||||
private messageErrorActions?: IMessageErrorActions | null;
|
||||
private messageActions?: IMessageActions | null;
|
||||
// Type of InteractionManager.runAfterInteractions
|
||||
private didMountInteraction?: {
|
||||
then: (onfulfilled?: (() => any) | undefined, onrejected?: (() => any) | undefined) => Promise<any>;
|
||||
done: (...args: any[]) => any;
|
||||
cancel: () => void;
|
||||
};
|
||||
private sub?: RoomClass;
|
||||
|
||||
constructor(props: IRoomViewProps) {
|
||||
super(props);
|
||||
|
@ -312,6 +321,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
if (member.statusText !== nextState.member.statusText) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const stateUpdated = stateAttrsUpdate.some(key => nextState[key] !== state[key]);
|
||||
if (stateUpdated) {
|
||||
return true;
|
||||
|
@ -340,8 +350,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
if (appState === 'foreground' && appState !== prevProps.appState && this.rid) {
|
||||
// Fire List.query() just to keep observables working
|
||||
if (this.list && this.list.current) {
|
||||
// @ts-ignore TODO: is this working?
|
||||
this.list.current?.query?.();
|
||||
this.list.current?.query();
|
||||
}
|
||||
}
|
||||
// If it's not direct message
|
||||
|
@ -379,7 +388,6 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
const db = database.active;
|
||||
this.mounted = false;
|
||||
if (!editing && this.messagebox && this.messagebox.current) {
|
||||
// @ts-ignore
|
||||
const { text } = this.messagebox.current;
|
||||
let obj: TSubscriptionModel | TThreadModel | null = null;
|
||||
if (this.tmid) {
|
||||
|
@ -394,9 +402,9 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
}
|
||||
if (obj) {
|
||||
try {
|
||||
const object = obj;
|
||||
await db.write(async () => {
|
||||
// FIXME: why do I need to tell ts this is non null if we have that if condition above?
|
||||
await obj!.update(r => {
|
||||
await object.update(r => {
|
||||
r.draftMessage = text;
|
||||
});
|
||||
});
|
||||
|
@ -543,20 +551,18 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
});
|
||||
};
|
||||
|
||||
goRoomActionsView = (screen?: string) => {
|
||||
goRoomActionsView = (screen?: keyof ModalStackParamList) => {
|
||||
logEvent(events.ROOM_GO_RA);
|
||||
const { room, member, joined } = this.state;
|
||||
const { navigation, isMasterDetail } = this.props;
|
||||
if (isMasterDetail) {
|
||||
// @ts-ignore TODO: find a way to make it work
|
||||
navigation.navigate('ModalStackNavigator', {
|
||||
// @ts-ignore
|
||||
navigation.navigate('ModalStackNavigator', {
|
||||
screen: screen ?? 'RoomActionsView',
|
||||
params: {
|
||||
rid: this.rid as string,
|
||||
t: this.t as SubscriptionType,
|
||||
// @ts-ignore
|
||||
room,
|
||||
room: room as ISubscription,
|
||||
member,
|
||||
showCloseModal: !!screen,
|
||||
joined
|
||||
|
@ -695,7 +701,6 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
};
|
||||
|
||||
errorActionsShow = (message: TAnyMessageModel) => {
|
||||
// @ts-ignore
|
||||
this.messageErrorActions?.showMessageErrorActions(message);
|
||||
};
|
||||
|
||||
|
@ -745,7 +750,6 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
};
|
||||
|
||||
onMessageLongPress = (message: TAnyMessageModel) => {
|
||||
// @ts-ignore
|
||||
this.messageActions?.showMessageActions(message);
|
||||
};
|
||||
|
||||
|
@ -875,10 +879,8 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
if (message.fromServer && !message.tmid && this.rid) {
|
||||
await loadSurroundingMessages({ messageId, rid: this.rid });
|
||||
}
|
||||
// @ts-ignore
|
||||
await Promise.race([this.list.current.jumpToMessage(message.id), new Promise(res => setTimeout(res, 5000))]);
|
||||
// @ts-ignore
|
||||
this.list.current.cancelJumpToMessage();
|
||||
await Promise.race([this.list.current?.jumpToMessage(message.id), new Promise(res => setTimeout(res, 5000))]);
|
||||
this.list.current?.cancelJumpToMessage();
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
|
@ -920,8 +922,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
const { user } = this.props;
|
||||
sendMessage(rid, message, this.tmid || tmid, user, tshow).then(() => {
|
||||
if (this.list && this.list.current) {
|
||||
// @ts-ignore
|
||||
this.list.current.update();
|
||||
this.list.current?.update();
|
||||
}
|
||||
this.setLastOpen(null);
|
||||
Review.pushPositiveEvent();
|
||||
|
@ -959,7 +960,6 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
} else {
|
||||
const { joinCodeRequired, rid } = room;
|
||||
if (joinCodeRequired) {
|
||||
// @ts-ignore
|
||||
this.joinCode.current?.show();
|
||||
} else {
|
||||
await Services.joinRoom(rid, null, this.t as any);
|
||||
|
@ -1102,20 +1102,20 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
if (handleCommandScroll(event)) {
|
||||
const offset = input === 'UIKeyInputUpArrow' ? 100 : -100;
|
||||
this.offset += offset;
|
||||
// @ts-ignore
|
||||
this.flatList?.scrollToOffset({ offset: this.offset });
|
||||
this.flatList?.current?.scrollToOffset({ offset: this.offset });
|
||||
} else if (handleCommandRoomActions(event)) {
|
||||
this.goRoomActionsView();
|
||||
} else if (handleCommandSearchMessages(event)) {
|
||||
this.goRoomActionsView('SearchMessagesView');
|
||||
} else if (handleCommandReplyLatest(event)) {
|
||||
if (this.list && this.list.current) {
|
||||
// @ts-ignore
|
||||
const message = this.list.current.getLastMessage();
|
||||
if (message) {
|
||||
this.onReplyInit(message, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
blockAction = ({
|
||||
|
@ -1360,7 +1360,6 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
return (
|
||||
<>
|
||||
<MessageActions
|
||||
// @ts-ignore
|
||||
ref={ref => (this.messageActions = ref)}
|
||||
tmid={this.tmid}
|
||||
room={room}
|
||||
|
@ -1371,7 +1370,6 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
onReactionPress={this.onReactionPress}
|
||||
isReadOnly={readOnly}
|
||||
/>
|
||||
{/* @ts-ignore TODO: missing interface on MessageErrorActions */}
|
||||
<MessageErrorActions ref={ref => (this.messageErrorActions = ref)} tmid={this.tmid} />
|
||||
</>
|
||||
);
|
||||
|
@ -1396,11 +1394,9 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
<StatusBar />
|
||||
<Banner title={I18n.t('Announcement')} text={announcement} bannerClosed={bannerClosed} closeBanner={this.closeBanner} />
|
||||
<List
|
||||
// @ts-ignore
|
||||
ref={this.list}
|
||||
listRef={this.flatList}
|
||||
rid={rid}
|
||||
t={t}
|
||||
tmid={this.tmid}
|
||||
theme={theme}
|
||||
tunread={tunread}
|
||||
|
|
Loading…
Reference in New Issue