From e9e6269da7487c7b3456b149d757e08760db6136 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Sat, 14 Aug 2021 10:31:18 +0200 Subject: [PATCH] Migrat ReadReceiptMarker to TypeScript --- src/components/views/rooms/EventTile.tsx | 1 + ...ReceiptMarker.js => ReadReceiptMarker.tsx} | 114 ++++++++++-------- 2 files changed, 64 insertions(+), 51 deletions(-) rename src/components/views/rooms/{ReadReceiptMarker.js => ReadReceiptMarker.tsx} (74%) diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index 301e33ec42..c5fbb99ede 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -240,6 +240,7 @@ interface IProps { // opaque readreceipt info for each userId; used by ReadReceiptMarker // to manage its animations. Should be an empty object when the room // first loads + // TODO: Proper typing for RR info readReceiptMap?: any; // A function which is used to check if the parent panel is being diff --git a/src/components/views/rooms/ReadReceiptMarker.js b/src/components/views/rooms/ReadReceiptMarker.tsx similarity index 74% rename from src/components/views/rooms/ReadReceiptMarker.js rename to src/components/views/rooms/ReadReceiptMarker.tsx index c9688b4d29..11e7563f11 100644 --- a/src/components/views/rooms/ReadReceiptMarker.js +++ b/src/components/views/rooms/ReadReceiptMarker.tsx @@ -16,7 +16,8 @@ limitations under the License. */ import React, { createRef } from 'react'; -import PropTypes from 'prop-types'; +import { RoomMember } from 'matrix-js-sdk/src'; + import { _t } from '../../../languageHandler'; import { formatDate } from '../../../DateUtils'; import NodeAnimator from "../../../NodeAnimator"; @@ -24,53 +25,64 @@ import * as sdk from "../../../index"; import { toPx } from "../../../utils/units"; import { replaceableComponent } from "../../../utils/replaceableComponent"; +interface IProps { + // the RoomMember to show the RR for + member?: RoomMember; + // userId to fallback the avatar to + // if the member hasn't been loaded yet + fallbackUserId: string; + + // number of pixels to offset the avatar from the right of its parent; + // typically a negative value. + leftOffset?: number; + + // true to hide the avatar (it will still be animated) + hidden?: boolean; + + // don't animate this RR into position + suppressAnimation?: boolean; + + // an opaque object for storing information about this user's RR in + // this room + // TODO: proper typing for RR info + readReceiptInfo: any; + + // A function which is used to check if the parent panel is being + // unmounted, to avoid unnecessary work. Should return true if we + // are being unmounted. + checkUnmounting?: () => boolean; + + // callback for clicks on this RR + onClick?: (e: React.MouseEvent) => void; + + // Timestamp when the receipt was read + timestamp?: number; + + // True to show twelve hour format, false otherwise + showTwelveHour?: boolean; +} + +interface IState { + suppressDisplay: boolean; + startStyles?: IReadReceiptMarkerStyle[]; +} + +interface IReadReceiptMarkerStyle { + top: number; + left: number; +} + @replaceableComponent("views.rooms.ReadReceiptMarker") -export default class ReadReceiptMarker extends React.PureComponent { - static propTypes = { - // the RoomMember to show the RR for - member: PropTypes.object, - // userId to fallback the avatar to - // if the member hasn't been loaded yet - fallbackUserId: PropTypes.string.isRequired, - - // number of pixels to offset the avatar from the right of its parent; - // typically a negative value. - leftOffset: PropTypes.number, - - // true to hide the avatar (it will still be animated) - hidden: PropTypes.bool, - - // don't animate this RR into position - suppressAnimation: PropTypes.bool, - - // an opaque object for storing information about this user's RR in - // this room - readReceiptInfo: PropTypes.object, - - // A function which is used to check if the parent panel is being - // unmounted, to avoid unnecessary work. Should return true if we - // are being unmounted. - checkUnmounting: PropTypes.func, - - // callback for clicks on this RR - onClick: PropTypes.func, - - // Timestamp when the receipt was read - timestamp: PropTypes.number, - - // True to show twelve hour format, false otherwise - showTwelveHour: PropTypes.bool, - }; +export default class ReadReceiptMarker extends React.PureComponent { + private avatar: React.RefObject = createRef(); static defaultProps = { leftOffset: 0, }; - constructor(props) { + constructor(props: IProps) { super(props); - this._avatar = createRef(); - this.state = { // if we are going to animate the RR, we don't show it on first render, // and instead just add a placeholder to the DOM; once we've been @@ -80,7 +92,7 @@ export default class ReadReceiptMarker extends React.PureComponent { }; } - componentWillUnmount() { + public componentWillUnmount(): void { // before we remove the rr, store its location in the map, so that if // it reappears, it can be animated from the right place. const rrInfo = this.props.readReceiptInfo; @@ -95,29 +107,29 @@ export default class ReadReceiptMarker extends React.PureComponent { return; } - const avatarNode = this._avatar.current; + const avatarNode = this.avatar.current; rrInfo.top = avatarNode.offsetTop; rrInfo.left = avatarNode.offsetLeft; rrInfo.parent = avatarNode.offsetParent; } - componentDidMount() { + public componentDidMount(): void { if (!this.state.suppressDisplay) { // we've already done our display - nothing more to do. return; } - this._animateMarker(); + this.animateMarker(); } - componentDidUpdate(prevProps) { + public componentDidUpdate(prevProps: IProps): void { const differentLeftOffset = prevProps.leftOffset !== this.props.leftOffset; const visibilityChanged = prevProps.hidden !== this.props.hidden; if (differentLeftOffset || visibilityChanged) { - this._animateMarker(); + this.animateMarker(); } } - _animateMarker() { + private animateMarker(): void { // treat new RRs as though they were off the top of the screen let oldTop = -15; @@ -126,7 +138,7 @@ export default class ReadReceiptMarker extends React.PureComponent { oldTop = oldInfo.top + oldInfo.parent.getBoundingClientRect().top; } - const newElement = this._avatar.current; + const newElement = this.avatar.current; let startTopOffset; if (!newElement.offsetParent) { // this seems to happen sometimes for reasons I don't understand @@ -156,10 +168,10 @@ export default class ReadReceiptMarker extends React.PureComponent { }); } - render() { + public render(): JSX.Element { const MemberAvatar = sdk.getComponent('avatars.MemberAvatar'); if (this.state.suppressDisplay) { - return
; + return
; } const style = { @@ -198,7 +210,7 @@ export default class ReadReceiptMarker extends React.PureComponent { style={style} title={title} onClick={this.props.onClick} - inputRef={this._avatar} + inputRef={this.avatar} /> );