({
channelId,
selectedPostId,
targetMessageId,
targetReplyId,
targetThreadRootId,
}: ChannelRouteScreenProps)
| 94 | } |
| 95 | |
| 96 | export function ChannelRouteScreen({ |
| 97 | channelId, |
| 98 | selectedPostId, |
| 99 | targetMessageId, |
| 100 | targetReplyId, |
| 101 | targetThreadRootId, |
| 102 | }: ChannelRouteScreenProps) { |
| 103 | const { closeForumPost, goForumPost } = useAppNavigation(); |
| 104 | const channelsQuery = useChannelsQuery(); |
| 105 | const identityQuery = useIdentityQuery(); |
| 106 | const profileQuery = useProfileQuery(); |
| 107 | const channels = channelsQuery.data ?? []; |
| 108 | const activeChannel = |
| 109 | channels.find((channel) => channel.id === channelId) ?? null; |
| 110 | const [targetMessageEvents, setTargetMessageEvents] = React.useState< |
| 111 | RelayEvent[] |
| 112 | >(() => { |
| 113 | const cachedTarget = getCachedSearchHitEvent(targetMessageId); |
| 114 | return cachedTarget ? [cachedTarget] : []; |
| 115 | }); |
| 116 | |
| 117 | // Reset spliced target events when the channel context changes (channel |
| 118 | // switch or entering/leaving a forum post). Tied to channel identity rather |
| 119 | // than the route target so clearing the `messageId` param mid-channel keeps |
| 120 | // the deep-linked row in view. Seeded with the mount key so the initial |
| 121 | // cache-seeded events survive first commit; only a genuine channel change |
| 122 | // clears them. Declared before the fetch effect so a channel switch clears |
| 123 | // stale events before the new target is fetched. |
| 124 | const previousResetKeyRef = React.useRef<string>( |
| 125 | `${channelId}::${selectedPostId ?? ""}`, |
| 126 | ); |
| 127 | React.useEffect(() => { |
| 128 | const resetKey = `${channelId}::${selectedPostId ?? ""}`; |
| 129 | if (previousResetKeyRef.current === resetKey) return; |
| 130 | previousResetKeyRef.current = resetKey; |
| 131 | setTargetMessageEvents([]); |
| 132 | }, [channelId, selectedPostId]); |
| 133 | |
| 134 | React.useEffect(() => { |
| 135 | let isCancelled = false; |
| 136 | |
| 137 | // Don't wipe already-spliced target events just because the route target |
| 138 | // cleared (e.g. `onTargetReached` clears the `messageId` URL param once the |
| 139 | // row is centered). In a channel whose feed doesn't already contain the |
| 140 | // deep-linked message, the spliced event is the only copy — dropping it on |
| 141 | // param-clear blanks the timeline. Resetting on channel / forum-post change |
| 142 | // is handled by the effect below; here we only fetch when there's a target. |
| 143 | if ((!targetMessageId && !targetThreadRootId) || selectedPostId) { |
| 144 | return () => { |
| 145 | isCancelled = true; |
| 146 | }; |
| 147 | } |
| 148 | |
| 149 | const cachedTarget = getCachedSearchHitEvent(targetMessageId); |
| 150 | if (cachedTarget) { |
| 151 | setTargetMessageEvents((currentEvents) => |
| 152 | currentEvents.some((event) => event.id === cachedTarget.id) |
| 153 | ? currentEvents |
nothing calls this directly
no test coverage detected