Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Move pinned message hooks to a dedicated file
Browse files Browse the repository at this point in the history
  • Loading branch information
florianduros committed Aug 22, 2024
1 parent 099f06d commit ec1f05c
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 166 deletions.
2 changes: 1 addition & 1 deletion src/components/views/context_menus/RoomContextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import { RoomNotifState } from "../../../RoomNotifs";
import Modal from "../../../Modal";
import ExportDialog from "../dialogs/ExportDialog";
import { useFeatureEnabled } from "../../../hooks/useSettings";
import { usePinnedEvents } from "../right_panel/PinnedMessagesCard";
import { RightPanelPhases } from "../../../stores/right-panel/RightPanelStorePhases";
import { RoomSettingsTab } from "../dialogs/RoomSettingsDialog";
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
Expand All @@ -53,6 +52,7 @@ import { UIComponent } from "../../../settings/UIFeature";
import { DeveloperToolsOption } from "./DeveloperToolsOption";
import { tagRoom } from "../../../utils/room/tagRoom";
import { useIsVideoRoom } from "../../../utils/video-rooms";
import { usePinnedEvents } from "../../../hooks/usePinnedEvents";

interface IProps extends IContextMenuProps {
room: Room;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import HeaderButtons, { HeaderKind } from "./HeaderButtons";
import { RightPanelPhases } from "../../../stores/right-panel/RightPanelStorePhases";
import { ActionPayload } from "../../../dispatcher/payloads";
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
import { useReadPinnedEvents, usePinnedEvents } from "./PinnedMessagesCard";
import { showThreadPanel } from "../../../dispatcher/dispatch-actions/threads";
import SettingsStore from "../../../settings/SettingsStore";
import {
Expand All @@ -40,6 +39,7 @@ import { SummarizedNotificationState } from "../../../stores/notifications/Summa
import PosthogTrackers from "../../../PosthogTrackers";
import { ButtonEvent } from "../elements/AccessibleButton";
import { doesRoomOrThreadHaveUnreadMessages } from "../../../Unread";
import { usePinnedEvents, useReadPinnedEvents } from "../../../hooks/usePinnedEvents";

const ROOM_INFO_PHASES = [
RightPanelPhases.RoomSummary,
Expand Down
166 changes: 3 additions & 163 deletions src/components/views/right_panel/PinnedMessagesCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import React, { useCallback, useEffect, useState, JSX } from "react";
import {
Room,
RoomEvent,
RoomStateEvent,
MatrixEvent,
EventType,
RelationType,
EventTimeline,
} from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
import React, { useCallback, useEffect, JSX } from "react";
import { Room, MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
import { Button, Separator } from "@vector-im/compound-web";
import classNames from "classnames";
import PinIcon from "@vector-im/compound-design-tokens/assets/web/icons/pin";
Expand All @@ -33,9 +24,6 @@ import { _t } from "../../../languageHandler";
import BaseCard from "./BaseCard";
import Spinner from "../elements/Spinner";
import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
import PinningUtils from "../../../utils/PinningUtils";
import { useAsyncMemo } from "../../../hooks/useAsyncMemo";
import { PinnedEventTile } from "../rooms/PinnedEventTile";
import { useRoomState } from "../../../hooks/useRoomState";
import RoomContext, { TimelineRenderingType, useRoomContext } from "../../../contexts/RoomContext";
Expand All @@ -46,155 +34,7 @@ import { filterBoolean } from "../../../utils/arrays";
import Modal from "../../../Modal";
import { UnpinAllDialog } from "../dialogs/UnpinAllDialog";
import EmptyState from "./EmptyState";

/**
* Get the pinned event IDs from a room.
* @param room
*/
function getPinnedEventIds(room?: Room): string[] {
return (
room
?.getLiveTimeline()
.getState(EventTimeline.FORWARDS)
?.getStateEvents(EventType.RoomPinnedEvents, "")
?.getContent()?.pinned ?? []
);
}

/**
* Get the pinned event IDs from a room.
* @param room
*/
export const usePinnedEvents = (room?: Room): string[] => {
const [pinnedEvents, setPinnedEvents] = useState<string[]>(getPinnedEventIds(room));

// Update the pinned events when the room state changes
// Filter out events that are not pinned events
const update = useCallback(
(ev?: MatrixEvent) => {
if (ev && ev.getType() !== EventType.RoomPinnedEvents) return;
setPinnedEvents(getPinnedEventIds(room));
},
[room],
);

useTypedEventEmitter(room?.getLiveTimeline().getState(EventTimeline.FORWARDS), RoomStateEvent.Events, update);
useEffect(() => {
setPinnedEvents(getPinnedEventIds(room));
return () => {
setPinnedEvents([]);
};
}, [room]);
return pinnedEvents;
};

/**
* Get the read pinned event IDs from a room.
* @param room
*/
function getReadPinnedEventIds(room?: Room): Set<string> {
return new Set(room?.getAccountData(ReadPinsEventId)?.getContent()?.event_ids ?? []);
}

/**
* Get the read pinned event IDs from a room.
* @param room
*/
export const useReadPinnedEvents = (room?: Room): Set<string> => {
const [readPinnedEvents, setReadPinnedEvents] = useState<Set<string>>(new Set());

// Update the read pinned events when the room state changes
// Filter out events that are not read pinned events
const update = useCallback(
(ev?: MatrixEvent) => {
if (ev && ev.getType() !== ReadPinsEventId) return;
setReadPinnedEvents(getReadPinnedEventIds(room));
},
[room],
);

useTypedEventEmitter(room, RoomEvent.AccountData, update);
useEffect(() => {
setReadPinnedEvents(getReadPinnedEventIds(room));
return () => {
setReadPinnedEvents(new Set());
};
}, [room]);
return readPinnedEvents;
};

/**
* Fetch the pinned events
* @param room
* @param pinnedEventIds
*/
function useFetchedPinnedEvents(room: Room, pinnedEventIds: string[]): Array<MatrixEvent | null> | null {
const cli = useMatrixClientContext();

return useAsyncMemo(
() => {
const promises = pinnedEventIds.map(async (eventId): Promise<MatrixEvent | null> => {
const timelineSet = room.getUnfilteredTimelineSet();
// Get the event from the local timeline
const localEvent = timelineSet
?.getTimelineForEvent(eventId)
?.getEvents()
.find((e) => e.getId() === eventId);

// Decrypt the event if it's encrypted
// Can happen when the tab is refreshed and the pinned events card is opened directly
if (localEvent?.isEncrypted()) {
await cli.decryptEventIfNeeded(localEvent);
}

// If the event is available locally, return it if it's pinnable
// Otherwise, return null
if (localEvent) return PinningUtils.isPinnable(localEvent) ? localEvent : null;

try {
// The event is not available locally, so we fetch the event and latest edit in parallel
const [
evJson,
{
events: [edit],
},
] = await Promise.all([
cli.fetchRoomEvent(room.roomId, eventId),
cli.relations(room.roomId, eventId, RelationType.Replace, null, { limit: 1 }),
]);

const event = new MatrixEvent(evJson);

// Decrypt the event if it's encrypted
if (event.isEncrypted()) {
await cli.decryptEventIfNeeded(event);
}

// Handle poll events
await room.processPollEvents([event]);

const senderUserId = event.getSender();
if (senderUserId && PinningUtils.isPinnable(event)) {
// Inject sender information
event.sender = room.getMember(senderUserId);
// Also inject any edits we've found
if (edit) event.makeReplaced(edit);

return event;
}
} catch (err) {
logger.error("Error looking up pinned event " + eventId + " in room " + room.roomId);
logger.error(err);
}
return null;
});

return Promise.all(promises);
},
[cli, room, pinnedEventIds],
null,
);
}
import { useFetchedPinnedEvents, usePinnedEvents, useReadPinnedEvents } from "../../../hooks/usePinnedEvents";

/**
* List the pinned messages in a room inside a Card.
Expand Down
2 changes: 1 addition & 1 deletion src/components/views/right_panel/RoomSummaryCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ import { E2EStatus } from "../../../utils/ShieldUtils";
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext";
import { useFeatureEnabled } from "../../../hooks/useSettings";
import { usePinnedEvents } from "./PinnedMessagesCard";
import RoomName from "../elements/RoomName";
import ExportDialog from "../dialogs/ExportDialog";
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
Expand All @@ -81,6 +80,7 @@ import { Action } from "../../../dispatcher/actions";
import { Key } from "../../../Keyboard";
import { useTransition } from "../../../hooks/useTransition";
import { useIsVideoRoom } from "../../../utils/video-rooms";
import { usePinnedEvents } from "../../../hooks/usePinnedEvents";

interface IProps {
room: Room;
Expand Down
Loading

0 comments on commit ec1f05c

Please sign in to comment.