Pinned messages UI fixes

This commit is contained in:
Jamie
2026-01-13 12:01:07 -08:00
committed by GitHub
parent a27a87a934
commit 560224f516
14 changed files with 133 additions and 187 deletions

View File

@@ -946,7 +946,7 @@ export const getPropsForMessage = (
canDownload: canDownload(message, conversationSelector),
canEndPoll: canEndPoll(message),
canForward: canForward(message),
canPinMessages: canPinMessages(conversation),
canPinMessage: canPinMessage(conversation, message),
canReact: canReact(message, ourConversationId, conversationSelector),
canReply: canReply(message, ourConversationId, conversationSelector),
canRetry: hasErrors(message),
@@ -2414,6 +2414,19 @@ export function canPinMessages(conversation: ConversationType): boolean {
return conversation.type === 'direct' || canEditGroupInfo(conversation);
}
export function canPinMessage(
conversation: ConversationType,
message: ReadonlyMessageAttributesType
): boolean {
if (!canPinMessages(conversation)) {
return false;
}
if (isGiftBadge(message)) {
return false;
}
return true;
}
function getHasMaxPinnedMessages(
pinnedMessagesMessageIds: ReadonlyArray<string>
) {

View File

@@ -132,6 +132,10 @@ function getPinSender(props: MessagePropsType): PinSender {
};
}
function getLastPinId(pins: ReadonlyArray<Pin>): PinnedMessageId | null {
return pins.at(-1)?.id ?? null;
}
function getPrevPinId(
pins: ReadonlyArray<Pin>,
pinnedMessageId: PinnedMessageId
@@ -375,26 +379,45 @@ export const SmartPinnedMessagesBar = memo(function SmartPinnedMessagesBar() {
useConversationsActions();
const [current, setCurrent] = useState(() => {
return pins.at(0)?.id ?? null;
return getLastPinId(pins);
});
const isCurrentOutOfDate = useMemo(() => {
const [prevPins, setPrevPins] = useState(pins);
if (pins !== prevPins) {
// Needed for `expectedCurrent` which might update `current` in the same render
setPrevPins(pins);
}
const expectedCurrent = useMemo(() => {
const latestPinId = getLastPinId(pins);
// If `current` is null, use the latest pin id if we have one.
if (current == null) {
if (pins.length > 0) {
return true;
}
return false;
return latestPinId;
}
const hasMatch = pins.some(pin => {
return pin.id === current;
});
// If `current` is already the latest pin id, leave it.
if (current === latestPinId) {
return current;
}
return !hasMatch;
}, [current, pins]);
// Update `current` if it no longer exists.
const hasCurrent = pins.some(pin => pin.id === current);
if (!hasCurrent) {
return latestPinId;
}
if (isCurrentOutOfDate) {
setCurrent(pins.at(0)?.id ?? null);
// Update `current` if it was previously the latest and there's a new latest.
const prevLatestPinId = getLastPinId(prevPins);
if (prevLatestPinId === current && latestPinId != null) {
return latestPinId;
}
return current;
}, [current, pins, prevPins]);
if (current !== expectedCurrent) {
setCurrent(expectedCurrent);
}
const handleCurrentChange = useCallback(
@@ -410,9 +433,10 @@ export const SmartPinnedMessagesBar = memo(function SmartPinnedMessagesBar() {
if (current == null) {
return;
}
const prevPinId = getPrevPinId(pins, current);
if (prevPinId != null) {
setCurrent(prevPinId);
const updatedCurrent = getPrevPinId(pins, current) ?? getLastPinId(pins);
if (updatedCurrent != null) {
setCurrent(updatedCurrent);
}
},
[scrollToMessage, conversationId, pins, current]