diff --git a/src/components/views/elements/RoomName.tsx b/src/components/views/elements/RoomName.tsx new file mode 100644 index 0000000000..9178155d19 --- /dev/null +++ b/src/components/views/elements/RoomName.tsx @@ -0,0 +1,40 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import {useEffect, useState} from "react"; +import {Room} from "matrix-js-sdk/src/models/room"; + +import {useEventEmitter} from "../../../hooks/useEventEmitter"; + +interface IProps { + room: Room; + children?(name: string): JSX.Element; +} + +const RoomName = ({ room, children }: IProps): JSX.Element => { + const [name, setName] = useState(room?.name); + useEventEmitter(room, "Room.name", () => { + setName(room?.name); + }); + useEffect(() => { + setName(room?.name); + }, [room]); + + if (children) return children(name); + return name || ""; +}; + +export default RoomName; diff --git a/src/components/views/elements/RoomTopic.tsx b/src/components/views/elements/RoomTopic.tsx new file mode 100644 index 0000000000..fe8aa5a83d --- /dev/null +++ b/src/components/views/elements/RoomTopic.tsx @@ -0,0 +1,45 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React, {useEffect, useState} from "react"; +import {EventType} from "matrix-js-sdk/src/@types/event"; +import {Room} from "matrix-js-sdk/src/models/room"; + +import {useEventEmitter} from "../../../hooks/useEventEmitter"; +import {linkifyElement} from "../../../HtmlUtils"; + +interface IProps { + room?: Room; + children?(topic: string, ref: (element: HTMLElement) => void): JSX.Element; +} + +export const getTopic = room => room?.currentState?.getStateEvents(EventType.RoomTopic, "")?.getContent()?.topic; + +const RoomTopic = ({ room, children }: IProps): JSX.Element => { + const [topic, setTopic] = useState(getTopic(room)); + useEventEmitter(room.currentState, "RoomState.events", () => { + setTopic(getTopic(room)); + }); + useEffect(() => { + setTopic(getTopic(room)); + }, [room]); + + const ref = e => e && linkifyElement(e); + if (children) return children(topic, ref); + return { topic }; +}; + +export default RoomTopic; diff --git a/src/components/views/rooms/RoomHeader.js b/src/components/views/rooms/RoomHeader.js index 8eb8276630..93055c69f5 100644 --- a/src/components/views/rooms/RoomHeader.js +++ b/src/components/views/rooms/RoomHeader.js @@ -15,14 +15,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {createRef} from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import { _t } from '../../../languageHandler'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import RateLimitedFunc from '../../../ratelimitedfunc'; -import { linkifyElement } from '../../../HtmlUtils'; import {CancelButton} from './SimpleRoomHeader'; import SettingsStore from "../../../settings/SettingsStore"; import RoomHeaderButtons from '../right_panel/RoomHeaderButtons'; @@ -30,6 +29,8 @@ import E2EIcon from './E2EIcon'; import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar"; import {DefaultTagID} from "../../../stores/room-list/models"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; +import RoomTopic from "../elements/RoomTopic"; +import RoomName from "../elements/RoomName"; export default class RoomHeader extends React.Component { static propTypes = { @@ -52,35 +53,13 @@ export default class RoomHeader extends React.Component { onCancelClick: null, }; - constructor(props) { - super(props); - - this._topic = createRef(); - } - componentDidMount() { const cli = MatrixClientPeg.get(); cli.on("RoomState.events", this._onRoomStateEvents); cli.on("Room.accountData", this._onRoomAccountData); - - // When a room name occurs, RoomState.events is fired *before* - // room.name is updated. So we have to listen to Room.name as well as - // RoomState.events. - if (this.props.room) { - this.props.room.on("Room.name", this._onRoomNameChange); - } - } - - componentDidUpdate() { - if (this._topic.current) { - linkifyElement(this._topic.current); - } } componentWillUnmount() { - if (this.props.room) { - this.props.room.removeListener("Room.name", this._onRoomNameChange); - } const cli = MatrixClientPeg.get(); if (cli) { cli.removeListener("RoomState.events", this._onRoomStateEvents); @@ -109,10 +88,6 @@ export default class RoomHeader extends React.Component { this.forceUpdate(); }, 500); - _onRoomNameChange = (room) => { - this.forceUpdate(); - }; - _hasUnreadPins() { const currentPinEvent = this.props.room.currentState.getStateEvents("m.room.pinned_events", ''); if (!currentPinEvent) return false; @@ -170,29 +145,28 @@ export default class RoomHeader extends React.Component { } } - let roomName = _t("Join Room"); + let oobName = _t("Join Room"); if (this.props.oobData && this.props.oobData.name) { - roomName = this.props.oobData.name; - } else if (this.props.room) { - roomName = this.props.room.name; + oobName = this.props.oobData.name; } const textClasses = classNames('mx_RoomHeader_nametext', { mx_RoomHeader_settingsHint: settingsHint }); const name =
-
{ roomName }
+ + {(name) => { + const roomName = name || oobName; + return
{ roomName }
; + }} +
{ searchStatus }
; - let topic; - if (this.props.room) { - const ev = this.props.room.currentState.getStateEvents('m.room.topic', ''); - if (ev) { - topic = ev.getContent().topic; - } - } - const topicElement = -
{ topic }
; + const topicElement = + {(topic, ref) =>
+ { topic } +
} +
; let roomAvatar; if (this.props.room) {