Skip to content

[#835] Fix SSR hydration mismatch in Writer tab expired badge#854

Merged
realproject7 merged 2 commits intomainfrom
task/835-badge-hydration-fix
Apr 12, 2026
Merged

[#835] Fix SSR hydration mismatch in Writer tab expired badge#854
realproject7 merged 2 commits intomainfrom
task/835-badge-hydration-fix

Conversation

@realproject7
Copy link
Copy Markdown
Owner

Summary

  • Changed useState(checkExpired) to useState(false) — avoids calling Date.now() during server render which caused hydration mismatch near expiry boundary
  • Replaced 1-second setInterval polling with a single setTimeout targeting the exact expiry time — fires once when the storyline actually expires
  • Proper cleanup on unmount
  • Patch version bump 0.1.19 → 0.1.20

Fixes #835

Test plan

  • No React hydration mismatch warnings in console
  • Badge shows "active" for non-expired storylines, transitions to "expired" at the right time
  • Badge shows "complete" for sunset storylines
  • Badge shows "expired" immediately for already-expired storylines on page load

🤖 Generated with Claude Code

- Change useState(checkExpired) to useState(false) to avoid Date.now()
  during server render
- Replace 1-second setInterval with a single setTimeout targeting the
  exact expiry time
- Cleanup timeout on unmount

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 12, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
plotlink Ignored Ignored Apr 12, 2026 2:51am

Request Review

Copy link
Copy Markdown
Owner Author

@realproject7 realproject7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re2 APPROVE — Clean fix. useState(false) eliminates the SSR/client divergence, and the targeted setTimeout is a big improvement over 1-second polling. Edge cases (already expired, sunset, no deadline) handled correctly. Cleanup on unmount is proper.

Copy link
Copy Markdown
Collaborator

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES

Summary

The SSR fix is on the right track, but the new timeout-based effect introduces stale state: isExpired is never reset back to false when the underlying storyline becomes non-expired.

Findings

  • [medium] isExpired can remain stuck true after storyline data changes
    • File: src/app/profile/[address]/page.tsx:887
    • Suggestion: Reset isExpired inside the effect before the early returns / timeout setup, or otherwise derive the current non-expired state when storyline.sunset, storyline.has_deadline, or storyline.last_plot_time changes. Right now a row that was previously expired can keep rendering the expired badge after a deadline extension or prop change.

Decision

Requesting changes because the hydration fix should not introduce stale badge state on rerenders or data refreshes.

Reset isExpired to false when effect re-runs with changed props, so a
previously expired row correctly reverts to active after a deadline
extension or new plot.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE

Summary

The follow-up addresses the stale state regression: isExpired is now reset when storyline props change, while still avoiding the SSR hydration mismatch and interval polling.

Findings

  • [info] GitHub checks are still pending at review time (e2e, lint-and-typecheck, visual-regression)
    • File: PR #854
    • Suggestion: Let CI finish before merge.

Decision

Approved because the revised effect now preserves correct badge behavior across prop changes and matches issue #835 without reintroducing the original hydration problem.

@realproject7 realproject7 merged commit 6d05782 into main Apr 12, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Writer tab: useState(checkExpired) causes SSR hydration mismatch

2 participants