element-portable/src/hooks/usePermalinkMember.ts
David Langley 491f0cd08a
Change license (#13)
* Copyright headers 1

* Licence headers 2

* Copyright Headers 3

* Copyright Headers 4

* Copyright Headers 5

* Copyright Headers 6

* Copyright headers 7

* Add copyright headers for html and config file

* Replace license files and update package.json

* Update with CLA

* lint
2024-09-09 13:57:16 +00:00

126 lines
4.3 KiB
TypeScript

/*
Copyright 2024 New Vector Ltd.
Copyright 2023 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import { IMatrixProfile, MatrixEvent, Room, RoomMember } from "matrix-js-sdk/src/matrix";
import { useEffect, useState } from "react";
import { PillType } from "../components/views/elements/Pill";
import { SdkContextClass } from "../contexts/SDKContext";
import { PermalinkParts } from "../utils/permalinks/PermalinkConstructor";
const createMemberFromProfile = (userId: string, profile: IMatrixProfile): RoomMember => {
const member = new RoomMember("", userId);
member.name = profile.displayname ?? userId;
member.rawDisplayName = member.name;
member.events.member = {
getContent: () => {
return { avatar_url: profile.avatar_url };
},
getDirectionalContent: function () {
// eslint-disable-next-line
return this.getContent();
},
} as MatrixEvent;
return member;
};
/**
* Tries to determine the user Id of a permalink.
* In case of a user permalink it is the user id.
* In case of an event permalink it is the sender user Id of the event if that event is available.
* Otherwise returns null.
*
* @param type - pill type
* @param parseResult - permalink parse result
* @param event - permalink event, if available
* @returns permalink user Id. null if the Id cannot be determined.
*/
const determineUserId = (
type: PillType | null,
parseResult: PermalinkParts | null,
event: MatrixEvent | null,
): string | null => {
if (type === null) return null;
if (parseResult?.userId) return parseResult.userId;
if (event && [PillType.EventInSameRoom, PillType.EventInOtherRoom].includes(type)) {
return event.getSender() ?? null;
}
return null;
};
/**
* Tries to determine a RoomMember.
*
* @param userId - User Id to get the member for
* @param targetRoom - permalink target room
* @returns RoomMember of the target room if it exists.
* If sharing at least one room with the user, then the result will be the profile fetched via API.
* null in all other cases.
*/
const determineMember = (userId: string, targetRoom: Room): RoomMember | null => {
const targetRoomMember = targetRoom.getMember(userId);
if (targetRoomMember) return targetRoomMember;
const knownProfile = SdkContextClass.instance.userProfilesStore.getOnlyKnownProfile(userId);
if (knownProfile) {
return createMemberFromProfile(userId, knownProfile);
}
return null;
};
/**
* Hook to get the permalink member
*
* @param type - Permalink type
* @param parseResult - Permalink parse result
* @param targetRoom - Permalink target room {@link ./usePermalinkTargetRoom.ts}
* @param event - Permalink event
* @returns The permalink member:
* - The room member for a user mention
* - The sender for a permalink to an event in the same room
* - Null in other cases or the user cannot be loaded.
*/
export const usePermalinkMember = (
type: PillType | null,
parseResult: PermalinkParts | null,
targetRoom: Room | null,
event: MatrixEvent | null,
): RoomMember | null => {
// User mentions and permalinks to events in the same room require to know the user.
// If it cannot be initially determined, it will be looked up later by a memo hook.
const shouldLookUpUser = type && [PillType.UserMention, PillType.EventInSameRoom].includes(type);
const userId = determineUserId(type, parseResult, event);
const userInRoom = shouldLookUpUser && userId && targetRoom ? determineMember(userId, targetRoom) : null;
const [member, setMember] = useState<RoomMember | null>(userInRoom);
useEffect(() => {
if (!shouldLookUpUser || !userId || member) {
// nothing to do here
return;
}
const doProfileLookup = async (): Promise<void> => {
const fetchedProfile = await SdkContextClass.instance.userProfilesStore.fetchOnlyKnownProfile(userId);
if (fetchedProfile) {
const newMember = createMemberFromProfile(userId, fetchedProfile);
setMember(newMember);
}
};
doProfileLookup();
}, [member, shouldLookUpUser, targetRoom, userId]);
return member;
};