Skip to content

fix(react): stop impure Date calls during render + 2 lint cleanups - #8

Merged
Steel-tech merged 1 commit into
mainfrom
fix/render-purity-warnings
Jun 18, 2026
Merged

fix(react): stop impure Date calls during render + 2 lint cleanups#8
Steel-tech merged 1 commit into
mainfrom
fix/render-purity-warnings

Conversation

@Steel-tech

@Steel-tech Steel-tech commented Jun 18, 2026

Copy link
Copy Markdown
Owner

Burns down the high-confidence subset of the flagged lint warnings (the rest are deliberately left — see below).

Real bugs fixed

  • EstimatePdf computed EST-${Date.now()...} during render, so the estimate number changed on every re-render (and the date was the same impurity class). Both now stamp once at mount via useMemo.
  • ExpirationAlerts read Date.now() in render → captured once via lazy useState.

Cleanups

  • Removed a dead eslint-disable no-console in ErrorBoundary (the rule isn't enabled).
  • Wrapped a // Total Bid Estimate JSX text node in braces (it's intentional visible cyberpunk-style text, not a stray comment).

Verification

  • Lint 22 → 18 warnings, 0 errors · tsc clean · 74 tests · build OK.

Deliberately NOT fixed

The 18 remaining warnings are all react-hooks/set-state-in-effect — the standard "hydrate from localStorage after mount" pattern (you can't read localStorage during SSR). "Fixing" them means useSyncExternalStore boilerplate at ~14 sites with real regression risk; better as a focused burndown than churned blind. One (document-card) is a lint false-positive (it selects an existing icon, doesn't create a component).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Fixed estimate number generation to remain consistent in PDF exports
    • Corrected display text rendering in estimate results
    • Expiration alerts now maintain stable status during component lifecycle, preventing unintended status shifts as time progresses
  • Chores

    • Updated linting configuration in error handling

Two real render-purity bugs: EstimatePdf computed the estimate # from
Date.now() during render (so it changed on every re-render) and the date
likewise; ExpirationAlerts read Date.now() in render. Both now stamp once
at mount (useMemo / lazy useState). Also clears a dead eslint-disable in
ErrorBoundary and a // comment-textnode in EstimateResults.

Lint warnings 22 -> 18 (the rest are the localStorage-hydration
set-state-in-effect pattern, left for a deliberate burndown).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e6de60eb-783b-46f6-8f5b-eb918093a496

📥 Commits

Reviewing files that changed from the base of the PR and between 0dd55d1 and fe5bb30.

📒 Files selected for processing (4)
  • components/estimator/estimate-pdf.tsx
  • components/estimator/estimate-results.tsx
  • components/ui/error-boundary.tsx
  • components/vault/expiration-alerts.tsx
💤 Files with no reviewable changes (1)
  • components/ui/error-boundary.tsx

📝 Walkthrough

Walkthrough

Two components (estimate-pdf.tsx and expiration-alerts.tsx) replace render-time Date computations with React hooks (useMemo and useState) to produce stable values across re-renders. Additionally, a JS comment in estimate-results.tsx is converted to a rendered string literal, and an ESLint suppression comment is removed from error-boundary.tsx.

Changes

Stable Timestamps and Minor Fixes

Layer / File(s) Summary
Stable Date values via useMemo and useState
components/estimator/estimate-pdf.tsx, components/vault/expiration-alerts.tsx
estimate-pdf.tsx uses useMemo to compute today and estimateId once per mount from a single Date instance, rendering EST-{estimateId} in the printable header. expiration-alerts.tsx uses useState to fix now at mount so expiration bucket logic uses a stable timestamp across re-renders.
Rendered string literal and ESLint suppression removal
components/estimator/estimate-results.tsx, components/ui/error-boundary.tsx
The // Total Bid Estimate JS comment in estimate-results.tsx is changed to a rendered string node {"// Total Bid Estimate"}, making it visible in the UI. The eslint-disable-next-line no-console suppression is removed from error-boundary.tsx's componentDidCatch.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 A Date made once, not born anew each tick,
The estimate's ID won't flicker or skip.
useMemo and useState hold time still,
No shifting timestamps against our will.
Even a comment now shows its face —
The rabbit stamps stability in place! 🕰️

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: fixing impure Date calls during render and performing 2 lint cleanups, which directly aligns with the changeset across all four modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/render-purity-warnings

Comment @coderabbitai help to get the list of available commands and usage tips.

@Steel-tech
Steel-tech merged commit 9ac5702 into main Jun 18, 2026
1 of 2 checks passed
@Steel-tech
Steel-tech deleted the fix/render-purity-warnings branch June 18, 2026 07:18

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fe5bb30082

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

export function ExpirationAlerts({ documents }: ExpirationAlertsProps) {
const now = Date.now();
// Captured once at mount — Date.now() in render is impure.
const [now] = useState(() => Date.now());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep expiration thresholds current

When the vault page stays open across a threshold change, this frozen now keeps all bucket decisions tied to the initial mount time. app/vault/page.tsx keeps ExpirationAlerts mounted for the page lifetime, so a document that was 31 days out at load will not enter the <30 days alert on later refresh/rerender, and an 8-day document can remain in the warning bucket after it crosses 7 days or expires; the per-card status still recomputes from Date.now(), so the banner can disagree with the cards. Track current time with a refresh/remount trigger or derive it when recomputing buckets instead of storing it once.

Useful? React with 👍 / 👎.

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.

1 participant