fix(OneDateNavigator): revive persisted string dates before use#4733
Merged
Conversation
A date-navigator value restored from OneDataCollection persisted storage round-trips through JSON, so its `from`/`to` arrive as ISO strings rather than Date objects. OneDateNavigator's equality check and its trigger (label, granularity math) call Date methods like `.getTime()` on them, throwing `TypeError: from.getTime is not a function` on the second load of any collection that persists a `date-navigator` navigation filter. Revive `value`/`defaultValue` into real Date objects at the OneDateNavigator boundary, so every downstream consumer receives Dates. It's a no-op (returns the same reference) when the range already holds Date objects. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
✅ No New Circular DependenciesNo new circular dependencies detected. Current count: 0 |
Contributor
📦 Alpha Package Version PublishedUse Use |
Contributor
🔍 Visual review for your branch is published 🔍Here are the links to: |
Contributor
✅ No breaking public API changesNo public exports were removed, renamed, or had existing props/types changed in a breaking way compared to Comparing
|
Contributor
Coverage Report for packages/react
File Coverage
|
||||||||||||||||||||||||||||||||||||||||||||
sauldom102
marked this pull request as ready for review
July 17, 2026 09:59
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
OneDateNavigatorcrashes withTypeError: from.getTime is not a functionwhen itsvalue/defaultValuehas been restored from persistedOneDataCollectionstorage.Any
OneDataCollectionwith a versionedid(storage on) that declares adate-navigatornavigation filter persists the selected range tolocalStorage.navigationFiltersis in the persisted-feature allowlist (dataCollectionStorageFeatures), so the{ from: Date, to: Date }range is written viaJSON.stringify— turning the dates into ISO strings.On the next load, the storage restore path applies the parsed value straight back into live state:
That restored value flows into
OneDateNavigator, whose equality check and trigger callDatemethods on it:isSameDatePickerValue→a.value?.from.getTime()DateNavigatorTrigger→.from.getTime(),granularity.toString(value.value),getPrevNext(value.value)"2026-07-13T…".getTime()doesn't exist → crash. It reproduces on the second load (once a serialized range is sitting in storage); a clean first load works because the initial default is normalized through the filter'svalueConverter, which the restore path bypasses.Originally surfaced on Factorial's
/projects/contributors/listafter that collection adopted adate-navigatorfilter.Regression origin
This is a latent defect, not caused by any recent release. The two ingredients were introduced separately, and it became reproducible once both were present:
date-navigatornavigation filter.localStoragepersistence system, addednavigationFiltersto the persisted-feature set, and shippeddataCollectionLocalStorageHandlerwhichJSON.stringifys state on write and bareJSON.parses it on read with no date revival. From this commit on, any collection combining storage + adate-navigatorfilter is one reload away from the crash.isSameDatePickerValue, one of the two.getTime()sites that throw on a stringfrom.Fix
Revive
value/defaultValueinto realDateobjects at theOneDateNavigatorboundary (reviveDatePickerValue), so every downstream consumer — the equality check, the trigger label, granularity math — receivesDates regardless of where the value came from. It's a no-op that returns the same reference when the range already holdsDateobjects, so there's no added re-render churn.Fixing at this boundary (rather than only patching
isSameDatePickerValue) is deliberate: the trigger also calls.getTime()/granularity math, so a comparator-only patch would just relocate the crash.Tests
Added two regression tests to
OneDateNavigator.test.tsxcovering adefaultValueand a controlledvaluewhose dates were serialized to strings — both previously threw, now render"January 2023".vitest(OneDateNavigator + DatePickerPopup) — 16 passedoxlint/oxfmt --checkclean on changed filestscclean on changed files🤖 Generated with Claude Code