Fix pinned messages card saying nothing pinned while loading (#10385)

This commit is contained in:
Michael Telatynski 2023-03-15 12:47:21 +00:00 committed by GitHub
parent 0c38bd7beb
commit 87fb493783
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 70 additions and 43 deletions

View file

@ -45,50 +45,53 @@ interface IProps {
onClose(): void;
}
function getPinnedEventIds(room?: Room): string[] {
return room?.currentState.getStateEvents(EventType.RoomPinnedEvents, "")?.getContent()?.pinned ?? [];
}
export const usePinnedEvents = (room?: Room): string[] => {
const [pinnedEvents, setPinnedEvents] = useState<string[]>([]);
const [pinnedEvents, setPinnedEvents] = useState<string[]>(getPinnedEventIds(room));
const update = useCallback(
(ev?: MatrixEvent) => {
if (!room) return;
if (ev && ev.getType() !== EventType.RoomPinnedEvents) return;
setPinnedEvents(
room.currentState.getStateEvents(EventType.RoomPinnedEvents, "")?.getContent()?.pinned || [],
);
setPinnedEvents(getPinnedEventIds(room));
},
[room],
);
useTypedEventEmitter(room?.currentState, RoomStateEvent.Events, update);
useEffect(() => {
update();
setPinnedEvents(getPinnedEventIds(room));
return () => {
setPinnedEvents([]);
};
}, [update]);
}, [room]);
return pinnedEvents;
};
export const useReadPinnedEvents = (room: Room): Set<string> => {
function getReadPinnedEventIds(room?: Room): Set<string> {
return new Set(room.getAccountData(ReadPinsEventId)?.getContent()?.event_ids ?? []);
}
export const useReadPinnedEvents = (room?: Room): Set<string> => {
const [readPinnedEvents, setReadPinnedEvents] = useState<Set<string>>(new Set());
const update = useCallback(
(ev?: MatrixEvent) => {
if (!room) return;
if (ev && ev.getType() !== ReadPinsEventId) return;
const readPins = room.getAccountData(ReadPinsEventId)?.getContent()?.event_ids;
setReadPinnedEvents(new Set(readPins || []));
setReadPinnedEvents(getReadPinnedEventIds(room));
},
[room],
);
useTypedEventEmitter(room, RoomEvent.AccountData, update);
useEffect(() => {
update();
setReadPinnedEvents(getReadPinnedEventIds(room));
return () => {
setReadPinnedEvents(new Set());
};
}, [update]);
}, [room]);
return readPinnedEvents;
};
@ -157,34 +160,8 @@ const PinnedMessagesCard: React.FC<IProps> = ({ room, onClose, permalinkCreator
null,
);
let content;
if (!pinnedEvents) {
content = <Spinner />;
} else if (pinnedEvents.length > 0) {
const onUnpinClicked = async (event: MatrixEvent): Promise<void> => {
const pinnedEvents = room.currentState.getStateEvents(EventType.RoomPinnedEvents, "");
if (pinnedEvents?.getContent()?.pinned) {
const pinned = pinnedEvents.getContent().pinned;
const index = pinned.indexOf(event.getId());
if (index !== -1) {
pinned.splice(index, 1);
await cli.sendStateEvent(room.roomId, EventType.RoomPinnedEvents, { pinned }, "");
}
}
};
// show them in reverse, with latest pinned at the top
content = filterBoolean(pinnedEvents)
.reverse()
.map((ev) => (
<PinnedEventTile
key={ev.getId()}
event={ev}
onUnpinClicked={canUnpin ? () => onUnpinClicked(ev) : undefined}
permalinkCreator={permalinkCreator}
/>
));
} else {
let content: JSX.Element[] | JSX.Element | undefined;
if (!pinnedEventIds.length) {
content = (
<div className="mx_PinnedMessagesCard_empty_wrapper">
<div className="mx_PinnedMessagesCard_empty">
@ -215,6 +192,32 @@ const PinnedMessagesCard: React.FC<IProps> = ({ room, onClose, permalinkCreator
</div>
</div>
);
} else if (pinnedEvents?.length) {
const onUnpinClicked = async (event: MatrixEvent): Promise<void> => {
const pinnedEvents = room.currentState.getStateEvents(EventType.RoomPinnedEvents, "");
if (pinnedEvents?.getContent()?.pinned) {
const pinned = pinnedEvents.getContent().pinned;
const index = pinned.indexOf(event.getId());
if (index !== -1) {
pinned.splice(index, 1);
await cli.sendStateEvent(room.roomId, EventType.RoomPinnedEvents, { pinned }, "");
}
}
};
// show them in reverse, with latest pinned at the top
content = filterBoolean(pinnedEvents)
.reverse()
.map((ev) => (
<PinnedEventTile
key={ev.getId()}
event={ev}
onUnpinClicked={canUnpin ? () => onUnpinClicked(ev) : undefined}
permalinkCreator={permalinkCreator}
/>
));
} else {
content = <Spinner />;
}
return (

View file

@ -15,7 +15,7 @@ limitations under the License.
*/
import React from "react";
import { render, act, RenderResult } from "@testing-library/react";
import { render, act, RenderResult, fireEvent, waitForElementToBeRemoved, screen } from "@testing-library/react";
import { mocked } from "jest-mock";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType, RelationType, MsgType } from "matrix-js-sdk/src/@types/event";
@ -240,7 +240,7 @@ describe("<PinnedMessagesCard />", () => {
...PollResponseEvent.from([answers[option as number].id], poll.getId()!).serialize(),
event: true,
room: "!room:example.org",
user: user as string,
user,
}),
);
@ -284,4 +284,28 @@ describe("<PinnedMessagesCard />", () => {
expect(pinTile[0].querySelectorAll(".mx_PollOption_optionVoteCount")[0]).toHaveTextContent("2 votes");
expect([...pinTile[0].querySelectorAll(".mx_PollOption_optionVoteCount")].at(-1)).toHaveTextContent("1 vote");
});
it("should allow admins to unpin messages", async () => {
const nonLocalPins = [pin1];
const room = mkRoom([], nonLocalPins);
jest.spyOn(room.currentState, "mayClientSendStateEvent").mockReturnValue(true);
const sendStateEvent = jest.spyOn(cli, "sendStateEvent");
const pins = await mountPins(room);
const pinTile = pins.container.querySelectorAll(".mx_PinnedEventTile");
expect(pinTile).toHaveLength(1);
fireEvent.click(pinTile[0].querySelector(".mx_PinnedEventTile_unpinButton")!);
expect(sendStateEvent).toHaveBeenCalledWith(room.roomId, "m.room.pinned_events", { pinned: [] }, "");
nonLocalPins.pop();
await Promise.all([waitForElementToBeRemoved(pinTile[0]), emitPinUpdates(room)]);
});
it("should show spinner whilst loading", async () => {
const room = mkRoom([], [pin1]);
mountPins(room);
const spinner = await screen.findByTestId("spinner");
await waitForElementToBeRemoved(spinner);
});
});