11import { useSearchParams } from '@remix-run/react' ;
22import { subDays , subMonths } from 'date-fns' ;
3- import { useCallback , useMemo } from 'react' ;
3+ import { useCallback , useEffect , useState } from 'react' ;
44
55type StaticDateRange = { type : 'static' ; startDate : string ; endDate : string } ;
66type DynamicDateRange = { type : 'dynamic' ; fromNow : string } ;
@@ -17,39 +17,58 @@ function getDefaultRange(): { start: string; end: string } {
1717 return { start : toIso ( start ) , end : toIso ( end ) } ;
1818}
1919
20+ function parseQ ( qValue : string | null ) : { range : IsoRange ; compareRange : IsoRange | null } {
21+ if ( qValue ) {
22+ try {
23+ const obj = JSON . parse ( atob ( qValue ) ) as {
24+ range ?: { start ?: string ; end ?: string } | null ;
25+ compareRange ?: { start ?: string ; end ?: string } | null ;
26+ } ;
27+ if ( obj ?. range ?. start && obj ?. range ?. end ) {
28+ return {
29+ range : { start : obj . range . start , end : obj . range . end } ,
30+ compareRange :
31+ obj . compareRange ?. start && obj . compareRange ?. end
32+ ? { start : obj . compareRange . start , end : obj . compareRange . end }
33+ : null ,
34+ } ;
35+ }
36+ } catch {
37+ // ignore malformed q
38+ }
39+ }
40+ const defaults = getDefaultRange ( ) ;
41+ return { range : { start : defaults . start , end : defaults . end } , compareRange : null } ;
42+ }
43+
2044export function useDateRangeSearchParams ( ) {
2145 const [ searchParams , setSearchParams ] = useSearchParams ( ) ;
22- const parseQ = useCallback (
23- ( qValue : string | null ) : { range : IsoRange ; compareRange : IsoRange | null } => {
24- if ( qValue ) {
25- try {
26- const obj = JSON . parse ( atob ( qValue ) ) as {
27- range ?: { start ?: string ; end ?: string } | null ;
28- compareRange ?: { start ?: string ; end ?: string } | null ;
29- } ;
30- if ( obj ?. range ?. start && obj ?. range ?. end ) {
31- return {
32- range : { start : obj . range . start , end : obj . range . end } ,
33- compareRange :
34- obj . compareRange ?. start && obj . compareRange ?. end
35- ? { start : obj . compareRange . start , end : obj . compareRange . end }
36- : null ,
37- } ;
38- }
39- } catch {
40- // ignore malformed q
41- }
46+ const [ dateRangeState , setDateRangeState ] = useState ( ( ) => {
47+ // Initialize state with parsed values
48+ const qValue = searchParams . get ( 'q' ) ;
49+ return parseQ ( qValue ) ;
50+ } ) ;
51+
52+ // Parse and update state only when the parsed values actually change
53+ useEffect ( ( ) => {
54+ const qValue = searchParams . get ( 'q' ) ;
55+ const parsed = parseQ ( qValue ) ;
56+
57+ // Only update state if values actually changed
58+ setDateRangeState ( ( current ) => {
59+ if (
60+ current . range . start !== parsed . range . start ||
61+ current . range . end !== parsed . range . end ||
62+ current . compareRange ?. start !== parsed . compareRange ?. start ||
63+ current . compareRange ?. end !== parsed . compareRange ?. end
64+ ) {
65+ return parsed ;
4266 }
43- const defaults = getDefaultRange ( ) ;
44- return { range : { start : defaults . start , end : defaults . end } , compareRange : null } ;
45- } ,
46- [ ] ,
47- ) ;
67+ return current ;
68+ } ) ;
69+ } , [ searchParams , parseQ ] ) ;
4870
49- const { range, compareRange } = useMemo (
50- ( ) => parseQ ( searchParams . get ( 'q' ) ) ,
51- [ parseQ , searchParams ] ,
52- ) ;
71+ const { range, compareRange } = dateRangeState ;
5372
5473 const computeDynamicRange = useCallback ( ( fromNow : string ) : IsoRange => {
5574 const now = new Date ( ) ;
@@ -75,7 +94,7 @@ export function useDateRangeSearchParams() {
7594 params . delete ( 'end' ) ;
7695 return params ;
7796 } ,
78- [ parseQ ] ,
97+ [ ] ,
7998 ) ;
8099
81100 const setDateRangeFilter = useCallback (
@@ -95,7 +114,7 @@ export function useDateRangeSearchParams() {
95114 const dynamicRange = computeDynamicRange ( dateRange . fromNow ) ;
96115 return writeQ ( prev , { range : dynamicRange , compareRange : undefined } ) ;
97116 } ,
98- { replace : true } ,
117+ { replace : false } ,
99118 ) ;
100119 } ,
101120 [ computeDynamicRange , setSearchParams , writeQ ] ,
@@ -116,7 +135,7 @@ export function useDateRangeSearchParams() {
116135
117136 return writeQ ( prev , { compareRange : nextCompare } ) ;
118137 } ,
119- { replace : true } ,
138+ { replace : false } ,
120139 ) ;
121140 } ,
122141 [ computeDynamicRange , setSearchParams , writeQ ] ,
0 commit comments