fix(ui): move useCallback hook before early returns in IssueDetail

The handleChatImageClick useCallback (and its dependencies) was defined
after conditional early returns, violating React's rules of hooks and
causing "Rendered more hooks than during the previous render" crashes.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
dotta 2026-04-08 07:20:24 -05:00
parent d0920da459
commit f75c0c317c

View file

@ -1301,6 +1301,33 @@ export function IssueDetail() {
};
}, [archiveFromInbox, canQuickArchiveFromInbox, issue?.id]);
const isImageAttachment = (attachment: IssueAttachment) => attachment.contentType.startsWith("image/");
const attachmentList = attachments ?? [];
const imageAttachments = attachmentList.filter(isImageAttachment);
const nonImageAttachments = attachmentList.filter((a) => !isImageAttachment(a));
const handleChatImageClick = useCallback(
(src: string) => {
// Try exact contentPath match first
let idx = imageAttachments.findIndex((a) => a.contentPath === src);
if (idx < 0) {
// Try matching by asset ID extracted from /api/assets/{assetId}/content URLs
const assetMatch = src.match(/\/api\/assets\/([^/]+)\/content/);
if (assetMatch) {
idx = imageAttachments.findIndex((a) => a.assetId === assetMatch[1]);
}
}
if (idx >= 0) {
setGalleryIndex(idx);
setGalleryOpen(true);
} else {
// Image not in attachment list — open in new tab
window.open(src, "_blank");
}
},
[imageAttachments],
);
const copyIssueToClipboard = async () => {
if (!issue) return;
const decodeEntities = (text: string) => {
@ -1352,32 +1379,6 @@ export function IssueDetail() {
}
};
const isImageAttachment = (attachment: IssueAttachment) => attachment.contentType.startsWith("image/");
const attachmentList = attachments ?? [];
const imageAttachments = attachmentList.filter(isImageAttachment);
const nonImageAttachments = attachmentList.filter((a) => !isImageAttachment(a));
const handleChatImageClick = useCallback(
(src: string) => {
// Try exact contentPath match first
let idx = imageAttachments.findIndex((a) => a.contentPath === src);
if (idx < 0) {
// Try matching by asset ID extracted from /api/assets/{assetId}/content URLs
const assetMatch = src.match(/\/api\/assets\/([^/]+)\/content/);
if (assetMatch) {
idx = imageAttachments.findIndex((a) => a.assetId === assetMatch[1]);
}
}
if (idx >= 0) {
setGalleryIndex(idx);
setGalleryOpen(true);
} else {
// Image not in attachment list — open in new tab
window.open(src, "_blank");
}
},
[imageAttachments],
);
const hasAttachments = attachmentList.length > 0;
const attachmentUploadButton = (
<>