Merge remote-tracking branch 'upstream/develop' into fix/emoji-dupe/19073
This commit is contained in:
commit
9a2d61bf20
10 changed files with 205 additions and 175 deletions
|
@ -58,12 +58,19 @@ import { IState, RovingTabIndexProvider, useRovingTabIndex } from "../../accessi
|
|||
import { getDisplayAliasForRoom } from "./RoomDirectory";
|
||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||
import { useEventEmitterState } from "../../hooks/useEventEmitter";
|
||||
import { IOOBData } from "../../stores/ThreepidInviteStore";
|
||||
|
||||
interface IProps {
|
||||
space: Room;
|
||||
initialText?: string;
|
||||
additionalButtons?: ReactNode;
|
||||
showRoom(cli: MatrixClient, hierarchy: RoomHierarchy, roomId: string, autoJoin?: boolean): void;
|
||||
showRoom(
|
||||
cli: MatrixClient,
|
||||
hierarchy: RoomHierarchy,
|
||||
roomId: string,
|
||||
autoJoin?: boolean,
|
||||
roomType?: RoomType,
|
||||
): void;
|
||||
}
|
||||
|
||||
interface ITileProps {
|
||||
|
@ -72,7 +79,7 @@ interface ITileProps {
|
|||
selected?: boolean;
|
||||
numChildRooms?: number;
|
||||
hasPermissions?: boolean;
|
||||
onViewRoomClick(autoJoin: boolean): void;
|
||||
onViewRoomClick(autoJoin: boolean, roomType: RoomType): void;
|
||||
onToggleClick?(): void;
|
||||
}
|
||||
|
||||
|
@ -98,12 +105,12 @@ const Tile: React.FC<ITileProps> = ({
|
|||
const onPreviewClick = (ev: ButtonEvent) => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
onViewRoomClick(false);
|
||||
onViewRoomClick(false, room.room_type as RoomType);
|
||||
};
|
||||
const onJoinClick = (ev: ButtonEvent) => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
onViewRoomClick(true);
|
||||
onViewRoomClick(true, room.room_type as RoomType);
|
||||
};
|
||||
|
||||
let button;
|
||||
|
@ -280,7 +287,13 @@ const Tile: React.FC<ITileProps> = ({
|
|||
</li>;
|
||||
};
|
||||
|
||||
export const showRoom = (cli: MatrixClient, hierarchy: RoomHierarchy, roomId: string, autoJoin = false) => {
|
||||
export const showRoom = (
|
||||
cli: MatrixClient,
|
||||
hierarchy: RoomHierarchy,
|
||||
roomId: string,
|
||||
autoJoin = false,
|
||||
roomType?: RoomType,
|
||||
) => {
|
||||
const room = hierarchy.roomMap.get(roomId);
|
||||
|
||||
// Don't let the user view a room they won't be able to either peek or join:
|
||||
|
@ -305,7 +318,8 @@ export const showRoom = (cli: MatrixClient, hierarchy: RoomHierarchy, roomId: st
|
|||
avatarUrl: room.avatar_url,
|
||||
// XXX: This logic is duplicated from the JS SDK which would normally decide what the name is.
|
||||
name: room.name || roomAlias || _t("Unnamed room"),
|
||||
},
|
||||
roomType,
|
||||
} as IOOBData,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -315,7 +329,7 @@ interface IHierarchyLevelProps {
|
|||
hierarchy: RoomHierarchy;
|
||||
parents: Set<string>;
|
||||
selectedMap?: Map<string, Set<string>>;
|
||||
onViewRoomClick(roomId: string, autoJoin: boolean): void;
|
||||
onViewRoomClick(roomId: string, autoJoin: boolean, roomType?: RoomType): void;
|
||||
onToggleClick?(parentId: string, childId: string): void;
|
||||
}
|
||||
|
||||
|
@ -353,8 +367,8 @@ export const HierarchyLevel = ({
|
|||
room={room}
|
||||
suggested={hierarchy.isSuggested(root.room_id, room.room_id)}
|
||||
selected={selectedMap?.get(root.room_id)?.has(room.room_id)}
|
||||
onViewRoomClick={(autoJoin) => {
|
||||
onViewRoomClick(room.room_id, autoJoin);
|
||||
onViewRoomClick={(autoJoin, roomType) => {
|
||||
onViewRoomClick(room.room_id, autoJoin, roomType);
|
||||
}}
|
||||
hasPermissions={hasPermissions}
|
||||
onToggleClick={onToggleClick ? () => onToggleClick(root.room_id, room.room_id) : undefined}
|
||||
|
@ -373,8 +387,8 @@ export const HierarchyLevel = ({
|
|||
}).length}
|
||||
suggested={hierarchy.isSuggested(root.room_id, space.room_id)}
|
||||
selected={selectedMap?.get(root.room_id)?.has(space.room_id)}
|
||||
onViewRoomClick={(autoJoin) => {
|
||||
onViewRoomClick(space.room_id, autoJoin);
|
||||
onViewRoomClick={(autoJoin, roomType) => {
|
||||
onViewRoomClick(space.room_id, autoJoin, roomType);
|
||||
}}
|
||||
hasPermissions={hasPermissions}
|
||||
onToggleClick={onToggleClick ? () => onToggleClick(root.room_id, space.room_id) : undefined}
|
||||
|
@ -576,7 +590,7 @@ const SpaceHierarchy = ({
|
|||
const { loading, rooms, hierarchy, loadMore } = useSpaceSummary(space);
|
||||
|
||||
const filteredRoomSet = useMemo<Set<IHierarchyRoom>>(() => {
|
||||
if (!rooms.length) return new Set();
|
||||
if (!rooms?.length) return new Set();
|
||||
const lcQuery = query.toLowerCase().trim();
|
||||
if (!lcQuery) return new Set(rooms);
|
||||
|
||||
|
@ -652,8 +666,8 @@ const SpaceHierarchy = ({
|
|||
parents={new Set()}
|
||||
selectedMap={selected}
|
||||
onToggleClick={hasPermissions ? onToggleClick : undefined}
|
||||
onViewRoomClick={(roomId, autoJoin) => {
|
||||
showRoom(cli, hierarchy, roomId, autoJoin);
|
||||
onViewRoomClick={(roomId, autoJoin, roomType) => {
|
||||
showRoom(cli, hierarchy, roomId, autoJoin, roomType);
|
||||
}}
|
||||
/>
|
||||
</>;
|
||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
|
||||
import React from 'react';
|
||||
import { MatrixEvent, Room } from 'matrix-js-sdk/src';
|
||||
import { Thread } from 'matrix-js-sdk/src/models/thread';
|
||||
import { Thread, ThreadEvent } from 'matrix-js-sdk/src/models/thread';
|
||||
|
||||
import BaseCard from "../views/right_panel/BaseCard";
|
||||
import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
|
||||
|
@ -46,13 +46,13 @@ export default class ThreadPanel extends React.Component<IProps, IState> {
|
|||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
this.room.on("Thread.update", this.onThreadEventReceived);
|
||||
this.room.on("Thread.ready", this.onThreadEventReceived);
|
||||
this.room.on(ThreadEvent.Update, this.onThreadEventReceived);
|
||||
this.room.on(ThreadEvent.Ready, this.onThreadEventReceived);
|
||||
}
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
this.room.removeListener("Thread.update", this.onThreadEventReceived);
|
||||
this.room.removeListener("Thread.ready", this.onThreadEventReceived);
|
||||
this.room.removeListener(ThreadEvent.Update, this.onThreadEventReceived);
|
||||
this.room.removeListener(ThreadEvent.Ready, this.onThreadEventReceived);
|
||||
}
|
||||
|
||||
private onThreadEventReceived = () => this.updateThreads();
|
||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
|
||||
import React from 'react';
|
||||
import { MatrixEvent, Room } from 'matrix-js-sdk/src';
|
||||
import { Thread } from 'matrix-js-sdk/src/models/thread';
|
||||
import { Thread, ThreadEvent } from 'matrix-js-sdk/src/models/thread';
|
||||
|
||||
import BaseCard from "../views/right_panel/BaseCard";
|
||||
import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
|
||||
|
@ -99,15 +99,15 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
|||
thread = new Thread([mxEv], this.props.room, client);
|
||||
mxEv.setThread(thread);
|
||||
}
|
||||
thread.on("Thread.update", this.updateThread);
|
||||
thread.once("Thread.ready", this.updateThread);
|
||||
thread.on(ThreadEvent.Update, this.updateThread);
|
||||
thread.once(ThreadEvent.Ready, this.updateThread);
|
||||
this.updateThread(thread);
|
||||
};
|
||||
|
||||
private teardownThread = () => {
|
||||
if (this.state.thread) {
|
||||
this.state.thread.removeListener("Thread.update", this.updateThread);
|
||||
this.state.thread.removeListener("Thread.ready", this.updateThread);
|
||||
this.state.thread.removeListener(ThreadEvent.Update, this.updateThread);
|
||||
this.state.thread.removeListener(ThreadEvent.Ready, this.updateThread);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -135,7 +135,7 @@ export default class MemberEventListSummary extends React.Component<IProps> {
|
|||
|
||||
const desc = formatCommaSeparatedList(descs);
|
||||
|
||||
return _t('%(nameList)s %(transitionList)s', { nameList: nameList, transitionList: desc });
|
||||
return _t('%(nameList)s %(transitionList)s', { nameList, transitionList: desc });
|
||||
});
|
||||
|
||||
if (!summaries) {
|
||||
|
|
|
@ -106,31 +106,20 @@ export default class ReactionsRowButton extends React.PureComponent<IProps, ISta
|
|||
}
|
||||
|
||||
const room = this.context.getRoom(mxEvent.getRoomId());
|
||||
let label;
|
||||
let label: string;
|
||||
if (room) {
|
||||
const senders = [];
|
||||
for (const reactionEvent of reactionEvents) {
|
||||
const member = room.getMember(reactionEvent.getSender());
|
||||
const name = member ? member.name : reactionEvent.getSender();
|
||||
senders.push(name);
|
||||
senders.push(member?.name || reactionEvent.getSender());
|
||||
}
|
||||
label = _t(
|
||||
"<reactors/><reactedWith> reacted with %(content)s</reactedWith>",
|
||||
{
|
||||
content,
|
||||
},
|
||||
{
|
||||
reactors: () => {
|
||||
return formatCommaSeparatedList(senders, 6);
|
||||
},
|
||||
reactedWith: (sub) => {
|
||||
if (!content) {
|
||||
return null;
|
||||
|
||||
const reactors = formatCommaSeparatedList(senders, 6);
|
||||
if (content) {
|
||||
label = _t("%(reactors)s reacted with %(content)s", { reactors, content });
|
||||
} else {
|
||||
label = reactors;
|
||||
}
|
||||
return sub;
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
const isPeeking = room.getMyMembership() !== "join";
|
||||
return <AccessibleButton
|
||||
|
|
|
@ -21,7 +21,7 @@ import { EventType } from "matrix-js-sdk/src/@types/event";
|
|||
import { EventStatus, MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
import { Relations } from "matrix-js-sdk/src/models/relations";
|
||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||
import { Thread } from 'matrix-js-sdk/src/models/thread';
|
||||
import { Thread, ThreadEvent } from 'matrix-js-sdk/src/models/thread';
|
||||
|
||||
import ReplyThread from "../elements/ReplyThread";
|
||||
import { _t } from '../../../languageHandler';
|
||||
|
@ -464,8 +464,8 @@ export default class EventTile extends React.Component<IProps, IState> {
|
|||
}
|
||||
|
||||
if (SettingsStore.getValue("feature_thread")) {
|
||||
this.props.mxEvent.once("Thread.ready", this.updateThread);
|
||||
this.props.mxEvent.on("Thread.update", this.updateThread);
|
||||
this.props.mxEvent.once(ThreadEvent.Ready, this.updateThread);
|
||||
this.props.mxEvent.on(ThreadEvent.Update, this.updateThread);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,13 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from "react";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
import { MatrixError } from "matrix-js-sdk/src/http-api";
|
||||
import { EventType, RoomType } from "matrix-js-sdk/src/@types/event";
|
||||
import { IJoinRuleEventContent, JoinRule } from "matrix-js-sdk/src/@types/partials";
|
||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||
|
||||
import * as sdk from '../../../index';
|
||||
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
||||
import dis from '../../../dispatcher/dispatcher';
|
||||
|
@ -27,91 +32,102 @@ import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore
|
|||
import { UPDATE_EVENT } from "../../../stores/AsyncStore";
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import InviteReason from "../elements/InviteReason";
|
||||
import { IOOBData } from "../../../stores/ThreepidInviteStore";
|
||||
import Spinner from "../elements/Spinner";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
|
||||
const MemberEventHtmlReasonField = "io.element.html_reason";
|
||||
|
||||
const MessageCase = Object.freeze({
|
||||
NotLoggedIn: "NotLoggedIn",
|
||||
Joining: "Joining",
|
||||
Loading: "Loading",
|
||||
Rejecting: "Rejecting",
|
||||
Kicked: "Kicked",
|
||||
Banned: "Banned",
|
||||
OtherThreePIDError: "OtherThreePIDError",
|
||||
InvitedEmailNotFoundInAccount: "InvitedEmailNotFoundInAccount",
|
||||
InvitedEmailNoIdentityServer: "InvitedEmailNoIdentityServer",
|
||||
InvitedEmailMismatch: "InvitedEmailMismatch",
|
||||
Invite: "Invite",
|
||||
ViewingRoom: "ViewingRoom",
|
||||
RoomNotFound: "RoomNotFound",
|
||||
OtherError: "OtherError",
|
||||
});
|
||||
enum MessageCase {
|
||||
NotLoggedIn = "NotLoggedIn",
|
||||
Joining = "Joining",
|
||||
Loading = "Loading",
|
||||
Rejecting = "Rejecting",
|
||||
Kicked = "Kicked",
|
||||
Banned = "Banned",
|
||||
OtherThreePIDError = "OtherThreePIDError",
|
||||
InvitedEmailNotFoundInAccount = "InvitedEmailNotFoundInAccount",
|
||||
InvitedEmailNoIdentityServer = "InvitedEmailNoIdentityServer",
|
||||
InvitedEmailMismatch = "InvitedEmailMismatch",
|
||||
Invite = "Invite",
|
||||
ViewingRoom = "ViewingRoom",
|
||||
RoomNotFound = "RoomNotFound",
|
||||
OtherError = "OtherError",
|
||||
}
|
||||
|
||||
@replaceableComponent("views.rooms.RoomPreviewBar")
|
||||
export default class RoomPreviewBar extends React.Component {
|
||||
static propTypes = {
|
||||
onJoinClick: PropTypes.func,
|
||||
onRejectClick: PropTypes.func,
|
||||
onRejectAndIgnoreClick: PropTypes.func,
|
||||
onForgetClick: PropTypes.func,
|
||||
interface IProps {
|
||||
// if inviterName is specified, the preview bar will shown an invite to the room.
|
||||
// You should also specify onRejectClick if specifiying inviterName
|
||||
inviterName: PropTypes.string,
|
||||
// You should also specify onRejectClick if specifying inviterName
|
||||
inviterName?: string;
|
||||
|
||||
// If invited by 3rd party invite, the email address the invite was sent to
|
||||
invitedEmail: PropTypes.string,
|
||||
invitedEmail?: string;
|
||||
|
||||
// For third party invites, information passed about the room out-of-band
|
||||
oobData: PropTypes.object,
|
||||
oobData?: IOOBData;
|
||||
|
||||
// For third party invites, a URL for a 3pid invite signing service
|
||||
signUrl: PropTypes.string,
|
||||
signUrl?: string;
|
||||
|
||||
// A standard client/server API error object. If supplied, indicates that the
|
||||
// caller was unable to fetch details about the room for the given reason.
|
||||
error: PropTypes.object,
|
||||
error?: MatrixError;
|
||||
|
||||
canPreview: PropTypes.bool,
|
||||
previewLoading: PropTypes.bool,
|
||||
room: PropTypes.object,
|
||||
canPreview?: boolean;
|
||||
previewLoading?: boolean;
|
||||
room?: Room;
|
||||
|
||||
// When a spinner is present, a spinnerState can be specified to indicate the
|
||||
// purpose of the spinner.
|
||||
spinner: PropTypes.bool,
|
||||
spinnerState: PropTypes.oneOf(["joining"]),
|
||||
loading: PropTypes.bool,
|
||||
joining: PropTypes.bool,
|
||||
rejecting: PropTypes.bool,
|
||||
loading?: boolean;
|
||||
joining?: boolean;
|
||||
rejecting?: boolean;
|
||||
// The alias that was used to access this room, if appropriate
|
||||
// If given, this will be how the room is referred to (eg.
|
||||
// in error messages).
|
||||
roomAlias: PropTypes.string,
|
||||
};
|
||||
roomAlias?: string;
|
||||
|
||||
onJoinClick?(): void;
|
||||
onRejectClick?(): void;
|
||||
onRejectAndIgnoreClick?(): void;
|
||||
onForgetClick?(): void;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
busy: boolean;
|
||||
accountEmails?: string[];
|
||||
invitedEmailMxid?: string;
|
||||
threePidFetchError?: MatrixError;
|
||||
}
|
||||
|
||||
@replaceableComponent("views.rooms.RoomPreviewBar")
|
||||
export default class RoomPreviewBar extends React.Component<IProps, IState> {
|
||||
static defaultProps = {
|
||||
onJoinClick() {},
|
||||
};
|
||||
|
||||
state = {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
busy: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._checkInvitedEmail();
|
||||
CommunityPrototypeStore.instance.on(UPDATE_EVENT, this._onCommunityUpdate);
|
||||
this.checkInvitedEmail();
|
||||
CommunityPrototypeStore.instance.on(UPDATE_EVENT, this.onCommunityUpdate);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (this.props.invitedEmail !== prevProps.invitedEmail || this.props.inviterName !== prevProps.inviterName) {
|
||||
this._checkInvitedEmail();
|
||||
this.checkInvitedEmail();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
CommunityPrototypeStore.instance.off(UPDATE_EVENT, this._onCommunityUpdate);
|
||||
CommunityPrototypeStore.instance.off(UPDATE_EVENT, this.onCommunityUpdate);
|
||||
}
|
||||
|
||||
async _checkInvitedEmail() {
|
||||
private async checkInvitedEmail() {
|
||||
// If this is an invite and we've been told what email address was
|
||||
// invited, fetch the user's account emails and discovery bindings so we
|
||||
// can check them against the email that was invited.
|
||||
|
@ -121,8 +137,7 @@ export default class RoomPreviewBar extends React.Component {
|
|||
// Gather the account 3PIDs
|
||||
const account3pids = await MatrixClientPeg.get().getThreePids();
|
||||
this.setState({
|
||||
accountEmails: account3pids.threepids
|
||||
.filter(b => b.medium === 'email').map(b => b.address),
|
||||
accountEmails: account3pids.threepids.filter(b => b.medium === 'email').map(b => b.address),
|
||||
});
|
||||
// If we have an IS connected, use that to lookup the email and
|
||||
// check the bound MXID.
|
||||
|
@ -146,21 +161,21 @@ export default class RoomPreviewBar extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
_onCommunityUpdate = (roomId) => {
|
||||
private onCommunityUpdate = (roomId: string): void => {
|
||||
if (this.props.room && this.props.room.roomId !== roomId) {
|
||||
return;
|
||||
}
|
||||
this.forceUpdate(); // we have nothing to update
|
||||
};
|
||||
|
||||
_getMessageCase() {
|
||||
private getMessageCase(): MessageCase {
|
||||
const isGuest = MatrixClientPeg.get().isGuest();
|
||||
|
||||
if (isGuest) {
|
||||
return MessageCase.NotLoggedIn;
|
||||
}
|
||||
|
||||
const myMember = this._getMyMember();
|
||||
const myMember = this.getMyMember();
|
||||
|
||||
if (myMember) {
|
||||
if (myMember.isKicked()) {
|
||||
|
@ -195,7 +210,7 @@ export default class RoomPreviewBar extends React.Component {
|
|||
}
|
||||
return MessageCase.Invite;
|
||||
} else if (this.props.error) {
|
||||
if (this.props.error.errcode == 'M_NOT_FOUND') {
|
||||
if ((this.props.error as MatrixError).errcode == 'M_NOT_FOUND') {
|
||||
return MessageCase.RoomNotFound;
|
||||
} else {
|
||||
return MessageCase.OtherError;
|
||||
|
@ -205,8 +220,8 @@ export default class RoomPreviewBar extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
_getKickOrBanInfo() {
|
||||
const myMember = this._getMyMember();
|
||||
private getKickOrBanInfo(): { memberName?: string, reason?: string } {
|
||||
const myMember = this.getMyMember();
|
||||
if (!myMember) {
|
||||
return {};
|
||||
}
|
||||
|
@ -219,24 +234,19 @@ export default class RoomPreviewBar extends React.Component {
|
|||
return { memberName, reason };
|
||||
}
|
||||
|
||||
_joinRule() {
|
||||
const room = this.props.room;
|
||||
if (room) {
|
||||
const joinRules = room.currentState.getStateEvents('m.room.join_rules', '');
|
||||
if (joinRules) {
|
||||
return joinRules.getContent().join_rule;
|
||||
}
|
||||
}
|
||||
private joinRule(): JoinRule {
|
||||
return this.props.room?.currentState
|
||||
.getStateEvents(EventType.RoomJoinRules, "")?.getContent<IJoinRuleEventContent>().join_rule;
|
||||
}
|
||||
|
||||
_communityProfile() {
|
||||
private communityProfile(): { displayName?: string, avatarMxc?: string } {
|
||||
if (this.props.room) return CommunityPrototypeStore.instance.getInviteProfile(this.props.room.roomId);
|
||||
return { displayName: null, avatarMxc: null };
|
||||
}
|
||||
|
||||
_roomName(atStart = false) {
|
||||
private roomName(atStart = false): string {
|
||||
let name = this.props.room ? this.props.room.name : this.props.roomAlias;
|
||||
const profile = this._communityProfile();
|
||||
const profile = this.communityProfile();
|
||||
if (profile.displayName) name = profile.displayName;
|
||||
if (name) {
|
||||
return name;
|
||||
|
@ -247,14 +257,11 @@ export default class RoomPreviewBar extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
_getMyMember() {
|
||||
return (
|
||||
this.props.room &&
|
||||
this.props.room.getMember(MatrixClientPeg.get().getUserId())
|
||||
);
|
||||
private getMyMember(): RoomMember {
|
||||
return this.props.room?.getMember(MatrixClientPeg.get().getUserId());
|
||||
}
|
||||
|
||||
_getInviteMember() {
|
||||
private getInviteMember(): RoomMember {
|
||||
const { room } = this.props;
|
||||
if (!room) {
|
||||
return;
|
||||
|
@ -268,8 +275,8 @@ export default class RoomPreviewBar extends React.Component {
|
|||
return room.currentState.getMember(inviterUserId);
|
||||
}
|
||||
|
||||
_isDMInvite() {
|
||||
const myMember = this._getMyMember();
|
||||
private isDMInvite(): boolean {
|
||||
const myMember = this.getMyMember();
|
||||
if (!myMember) {
|
||||
return false;
|
||||
}
|
||||
|
@ -278,7 +285,7 @@ export default class RoomPreviewBar extends React.Component {
|
|||
return memberContent.membership === "invite" && memberContent.is_direct;
|
||||
}
|
||||
|
||||
_makeScreenAfterLogin() {
|
||||
private makeScreenAfterLogin(): { screen: string, params: Record<string, any> } {
|
||||
return {
|
||||
screen: 'room',
|
||||
params: {
|
||||
|
@ -291,18 +298,16 @@ export default class RoomPreviewBar extends React.Component {
|
|||
};
|
||||
}
|
||||
|
||||
onLoginClick = () => {
|
||||
dis.dispatch({ action: 'start_login', screenAfterLogin: this._makeScreenAfterLogin() });
|
||||
private onLoginClick = () => {
|
||||
dis.dispatch({ action: 'start_login', screenAfterLogin: this.makeScreenAfterLogin() });
|
||||
};
|
||||
|
||||
onRegisterClick = () => {
|
||||
dis.dispatch({ action: 'start_registration', screenAfterLogin: this._makeScreenAfterLogin() });
|
||||
private onRegisterClick = () => {
|
||||
dis.dispatch({ action: 'start_registration', screenAfterLogin: this.makeScreenAfterLogin() });
|
||||
};
|
||||
|
||||
render() {
|
||||
const brand = SdkConfig.get().brand;
|
||||
const Spinner = sdk.getComponent('elements.Spinner');
|
||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||
|
||||
let showSpinner = false;
|
||||
let title;
|
||||
|
@ -315,10 +320,10 @@ export default class RoomPreviewBar extends React.Component {
|
|||
let footer;
|
||||
const extraComponents = [];
|
||||
|
||||
const messageCase = this._getMessageCase();
|
||||
const messageCase = this.getMessageCase();
|
||||
switch (messageCase) {
|
||||
case MessageCase.Joining: {
|
||||
title = _t("Joining room …");
|
||||
title = this.props.oobData.roomType === RoomType.Space ? _t("Joining space …") : _t("Joining room …");
|
||||
showSpinner = true;
|
||||
break;
|
||||
}
|
||||
|
@ -349,12 +354,12 @@ export default class RoomPreviewBar extends React.Component {
|
|||
break;
|
||||
}
|
||||
case MessageCase.Kicked: {
|
||||
const { memberName, reason } = this._getKickOrBanInfo();
|
||||
const { memberName, reason } = this.getKickOrBanInfo();
|
||||
title = _t("You were kicked from %(roomName)s by %(memberName)s",
|
||||
{ memberName, roomName: this._roomName() });
|
||||
{ memberName, roomName: this.roomName() });
|
||||
subTitle = reason ? _t("Reason: %(reason)s", { reason }) : null;
|
||||
|
||||
if (this._joinRule() === "invite") {
|
||||
if (this.joinRule() === "invite") {
|
||||
primaryActionLabel = _t("Forget this room");
|
||||
primaryActionHandler = this.props.onForgetClick;
|
||||
} else {
|
||||
|
@ -366,9 +371,9 @@ export default class RoomPreviewBar extends React.Component {
|
|||
break;
|
||||
}
|
||||
case MessageCase.Banned: {
|
||||
const { memberName, reason } = this._getKickOrBanInfo();
|
||||
const { memberName, reason } = this.getKickOrBanInfo();
|
||||
title = _t("You were banned from %(roomName)s by %(memberName)s",
|
||||
{ memberName, roomName: this._roomName() });
|
||||
{ memberName, roomName: this.roomName() });
|
||||
subTitle = reason ? _t("Reason: %(reason)s", { reason }) : null;
|
||||
primaryActionLabel = _t("Forget this room");
|
||||
primaryActionHandler = this.props.onForgetClick;
|
||||
|
@ -376,8 +381,8 @@ export default class RoomPreviewBar extends React.Component {
|
|||
}
|
||||
case MessageCase.OtherThreePIDError: {
|
||||
title = _t("Something went wrong with your invite to %(roomName)s",
|
||||
{ roomName: this._roomName() });
|
||||
const joinRule = this._joinRule();
|
||||
{ roomName: this.roomName() });
|
||||
const joinRule = this.joinRule();
|
||||
const errCodeMessage = _t(
|
||||
"An error (%(errcode)s) was returned while trying to validate your " +
|
||||
"invite. You could try to pass this information on to a room admin.",
|
||||
|
@ -410,7 +415,7 @@ export default class RoomPreviewBar extends React.Component {
|
|||
"This invite to %(roomName)s was sent to %(email)s which is not " +
|
||||
"associated with your account",
|
||||
{
|
||||
roomName: this._roomName(),
|
||||
roomName: this.roomName(),
|
||||
email: this.props.invitedEmail,
|
||||
},
|
||||
);
|
||||
|
@ -427,7 +432,7 @@ export default class RoomPreviewBar extends React.Component {
|
|||
title = _t(
|
||||
"This invite to %(roomName)s was sent to %(email)s",
|
||||
{
|
||||
roomName: this._roomName(),
|
||||
roomName: this.roomName(),
|
||||
email: this.props.invitedEmail,
|
||||
},
|
||||
);
|
||||
|
@ -443,7 +448,7 @@ export default class RoomPreviewBar extends React.Component {
|
|||
title = _t(
|
||||
"This invite to %(roomName)s was sent to %(email)s",
|
||||
{
|
||||
roomName: this._roomName(),
|
||||
roomName: this.roomName(),
|
||||
email: this.props.invitedEmail,
|
||||
},
|
||||
);
|
||||
|
@ -458,11 +463,11 @@ export default class RoomPreviewBar extends React.Component {
|
|||
case MessageCase.Invite: {
|
||||
const RoomAvatar = sdk.getComponent("views.avatars.RoomAvatar");
|
||||
const oobData = Object.assign({}, this.props.oobData, {
|
||||
avatarUrl: this._communityProfile().avatarMxc,
|
||||
avatarUrl: this.communityProfile().avatarMxc,
|
||||
});
|
||||
const avatar = <RoomAvatar room={this.props.room} oobData={oobData} />;
|
||||
|
||||
const inviteMember = this._getInviteMember();
|
||||
const inviteMember = this.getInviteMember();
|
||||
let inviterElement;
|
||||
if (inviteMember) {
|
||||
inviterElement = <span>
|
||||
|
@ -474,7 +479,7 @@ export default class RoomPreviewBar extends React.Component {
|
|||
inviterElement = (<span className="mx_RoomPreviewBar_inviter">{ this.props.inviterName }</span>);
|
||||
}
|
||||
|
||||
const isDM = this._isDMInvite();
|
||||
const isDM = this.isDMInvite();
|
||||
if (isDM) {
|
||||
title = _t("Do you want to chat with %(user)s?",
|
||||
{ user: inviteMember.name });
|
||||
|
@ -485,7 +490,7 @@ export default class RoomPreviewBar extends React.Component {
|
|||
primaryActionLabel = _t("Start chatting");
|
||||
} else {
|
||||
title = _t("Do you want to join %(roomName)s?",
|
||||
{ roomName: this._roomName() });
|
||||
{ roomName: this.roomName() });
|
||||
subTitle = [
|
||||
avatar,
|
||||
_t("<userName/> invited you", {}, { userName: () => inviterElement }),
|
||||
|
@ -519,22 +524,22 @@ export default class RoomPreviewBar extends React.Component {
|
|||
case MessageCase.ViewingRoom: {
|
||||
if (this.props.canPreview) {
|
||||
title = _t("You're previewing %(roomName)s. Want to join it?",
|
||||
{ roomName: this._roomName() });
|
||||
{ roomName: this.roomName() });
|
||||
} else {
|
||||
title = _t("%(roomName)s can't be previewed. Do you want to join it?",
|
||||
{ roomName: this._roomName(true) });
|
||||
{ roomName: this.roomName(true) });
|
||||
}
|
||||
primaryActionLabel = _t("Join the discussion");
|
||||
primaryActionHandler = this.props.onJoinClick;
|
||||
break;
|
||||
}
|
||||
case MessageCase.RoomNotFound: {
|
||||
title = _t("%(roomName)s does not exist.", { roomName: this._roomName(true) });
|
||||
title = _t("%(roomName)s does not exist.", { roomName: this.roomName(true) });
|
||||
subTitle = _t("This room doesn't exist. Are you sure you're at the right place?");
|
||||
break;
|
||||
}
|
||||
case MessageCase.OtherError: {
|
||||
title = _t("%(roomName)s is not accessible at this time.", { roomName: this._roomName(true) });
|
||||
title = _t("%(roomName)s is not accessible at this time.", { roomName: this.roomName(true) });
|
||||
subTitle = [
|
||||
_t("Try again later, or ask a room admin to check if you have access."),
|
||||
_t(
|
|
@ -1660,6 +1660,7 @@
|
|||
"%(count)s results|other": "%(count)s results",
|
||||
"%(count)s results|one": "%(count)s result",
|
||||
"This room": "This room",
|
||||
"Joining space …": "Joining space …",
|
||||
"Joining room …": "Joining room …",
|
||||
"Loading …": "Loading …",
|
||||
"Rejecting invite …": "Rejecting invite …",
|
||||
|
@ -1976,7 +1977,7 @@
|
|||
"Add reaction": "Add reaction",
|
||||
"Show all": "Show all",
|
||||
"Reactions": "Reactions",
|
||||
"<reactors/><reactedWith> reacted with %(content)s</reactedWith>": "<reactors/><reactedWith> reacted with %(content)s</reactedWith>",
|
||||
"%(reactors)s reacted with %(content)s": "%(reactors)s reacted with %(content)s",
|
||||
"<reactors/><reactedWith>reacted with %(shortName)s</reactedWith>": "<reactors/><reactedWith>reacted with %(shortName)s</reactedWith>",
|
||||
"Message deleted": "Message deleted",
|
||||
"Message deleted by %(name)s": "Message deleted by %(name)s",
|
||||
|
|
|
@ -16,6 +16,7 @@ limitations under the License.
|
|||
|
||||
import EventEmitter from "events";
|
||||
import { base32 } from "rfc4648";
|
||||
import { RoomType } from "matrix-js-sdk/src/@types/event";
|
||||
|
||||
// Dev note: the interface is split in two so we don't have to disable the
|
||||
// linter across the whole project.
|
||||
|
@ -53,6 +54,9 @@ export interface IOOBData {
|
|||
name?: string; // The room's name
|
||||
avatarUrl?: string; // The mxc:// avatar URL for the room
|
||||
inviterName?: string; // The display name of the person who invited us to the room
|
||||
// eslint-disable-next-line camelcase
|
||||
room_name?: string; // The name of the room, to be used until we are told better by the server
|
||||
roomType?: RoomType; // The type of the room, to be used until we are told better by the server
|
||||
}
|
||||
|
||||
const STORAGE_PREFIX = "mx_threepid_invite_";
|
||||
|
|
|
@ -104,7 +104,10 @@ export function getUserNameColorClass(userId: string): string {
|
|||
* @returns {string} a string constructed by joining `items` with a comma
|
||||
* between each item, but with the last item appended as " and [lastItem]".
|
||||
*/
|
||||
export function formatCommaSeparatedList(items: Array<string | JSX.Element>, itemLimit?: number): string | JSX.Element {
|
||||
export function formatCommaSeparatedList(items: string[], itemLimit?: number): string;
|
||||
export function formatCommaSeparatedList(items: JSX.Element[], itemLimit?: number): JSX.Element;
|
||||
export function formatCommaSeparatedList(items: Array<JSX.Element | string>, itemLimit?: number): JSX.Element | string;
|
||||
export function formatCommaSeparatedList(items: Array<JSX.Element | string>, itemLimit?: number): JSX.Element | string {
|
||||
const remaining = itemLimit === undefined ? 0 : Math.max(
|
||||
items.length - itemLimit, 0,
|
||||
);
|
||||
|
@ -112,11 +115,25 @@ export function formatCommaSeparatedList(items: Array<string | JSX.Element>, ite
|
|||
return "";
|
||||
} else if (items.length === 1) {
|
||||
return items[0];
|
||||
} else if (remaining > 0) {
|
||||
items = items.slice(0, itemLimit);
|
||||
return _t("%(items)s and %(count)s others", { items: jsxJoin(items, ', '), count: remaining } );
|
||||
} else {
|
||||
const lastItem = items.pop();
|
||||
return _t("%(items)s and %(lastItem)s", { items: jsxJoin(items, ', '), lastItem: lastItem });
|
||||
let lastItem;
|
||||
if (remaining > 0) {
|
||||
items = items.slice(0, itemLimit);
|
||||
} else {
|
||||
lastItem = items.pop();
|
||||
}
|
||||
|
||||
let joinedItems;
|
||||
if (items.every(e => typeof e === "string")) {
|
||||
joinedItems = items.join(", ");
|
||||
} else {
|
||||
joinedItems = jsxJoin(items, ", ");
|
||||
}
|
||||
|
||||
if (remaining > 0) {
|
||||
return _t("%(items)s and %(count)s others", { items: joinedItems, count: remaining } );
|
||||
} else {
|
||||
return _t("%(items)s and %(lastItem)s", { items: joinedItems, lastItem });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue