From 5fe82b24896fa56d1db77c47dd37c9fcfb1385bc Mon Sep 17 00:00:00 2001 From: soyalejolopez <88358406+soyalejolopez@users.noreply.github.com> Date: Thu, 23 Jul 2026 16:34:48 -0500 Subject: [PATCH] Fix giscus like button not persisting first reaction (#1312) The report detail page embeds giscus for likes. On resources with no backing Discussion yet, the first reaction hit giscus bug #1312: giscus creates the discussion and adds the reaction server-side but never refetches, so the like visually reverts until a manual refresh. Fix the existing workaround so the remount reliably fires: - Event-driven remount: track whether a discussion existed at mount time and remount once when metadata reports it was just created by the user's reaction. - Remove the self-defeating hasDiscussion re-check from the blur-timer callback (it cancelled the very remount meant to persist the like). - Re-arm recovery when a speculative (blur-triggered) refetch finds no discussion, so a later genuine first reaction can still stick. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 61593e5a-6c5f-46eb-bb43-08ee66fce301 --- index.html | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index 329a4f8..610de38 100644 --- a/index.html +++ b/index.html @@ -2334,7 +2334,13 @@

Browse all 54 scripts →

// fails to refetch, so the 👍 visually "reverts". We detect that the discussion // does not exist yet (via emit-metadata) and, once the user interacts, re-mount // giscus to pull the freshly-created discussion + reaction so it sticks. - const giscusState = { slug: null, hasDiscussion: false, refetched: false, pendingTimer: null }; + // existedAtMount: whether a backing discussion already existed the first time + // giscus reported metadata for the current slug (null = not yet known). It lets us + // tell a pre-existing discussion apart from one the user just created by reacting. + // speculativeRefetch: true when the current refetch was triggered by iframe focus + // (blur fallback) rather than an observed discussion creation, so we can re-arm if + // it turns out no discussion was actually created. + const giscusState = { slug: null, hasDiscussion: false, refetched: false, existedAtMount: null, speculativeRefetch: false, pendingTimer: null }; function giscusClearPending() { if (giscusState.pendingTimer) { clearTimeout(giscusState.pendingTimer); giscusState.pendingTimer = null; } @@ -2351,6 +2357,8 @@

Browse all 54 scripts →

} else { giscusState.hasDiscussion = false; giscusState.refetched = false; + giscusState.existedAtMount = null; + giscusState.speculativeRefetch = false; } const script = document.createElement('script'); script.src = "https://giscus.app/client.js"; @@ -2380,7 +2388,25 @@

Browse all 54 scripts →

const payload = event.data && event.data.giscus; if (!payload || !('discussion' in payload)) return; const d = payload.discussion; - giscusState.hasDiscussion = !!(d && d.id); + const exists = !!(d && d.id); + giscusState.hasDiscussion = exists; + // Record whether a discussion already existed the first time giscus reported in. + // Kept as a standalone `if` (not part of the chain below) so the re-arm branch can + // still run on the same message even when this is the first metadata we receive. + if (giscusState.existedAtMount === null) { + giscusState.existedAtMount = exists; + } + if (exists && giscusState.existedAtMount === false && !giscusState.refetched) { + // The discussion just came into existence — the user's first reaction created it + // (#1312). giscus won't refetch on its own, so remount once to make the 👍 stick. + giscusState.speculativeRefetch = false; + mountGiscus(giscusState.slug, document.documentElement.getAttribute('data-theme'), true); + } else if (!exists && giscusState.refetched && giscusState.speculativeRefetch) { + // A blur-triggered (speculative) refetch happened but there is still no discussion, + // so it was "wasted" (the iframe focus was a sign-in/comment, not a reaction). + // Re-arm recovery so a later genuine first reaction can still be refetched. + giscusState.refetched = false; + } }); // When the user clicks into the giscus iframe (e.g. to react) on a resource that @@ -2394,9 +2420,14 @@

Browse all 54 scripts →

if (!giscusState.slug || giscusState.hasDiscussion || giscusState.refetched || giscusState.pendingTimer) return; giscusState.pendingTimer = setTimeout(() => { giscusState.pendingTimer = null; - if (!giscusState.slug || giscusState.hasDiscussion || giscusState.refetched) return; + // Do NOT re-check hasDiscussion here: by now the reaction may have (just) created + // the discussion, which is exactly the case that needs a refetch. A remount is + // harmless (it only refetches current server state) and must fire so the 👍 sticks. + // Mark it speculative so we re-arm if it turns out no discussion was created. + if (!giscusState.slug || giscusState.refetched) return; + giscusState.speculativeRefetch = true; mountGiscus(giscusState.slug, document.documentElement.getAttribute('data-theme'), true); - }, 2500); + }, 3000); }, 0); });