Skip to content

Commit 520aa22

Browse files
committed
refactor(emcn): reset range calendar via key instead of render-phase resync
Replaces the imperative render-phase state reset with React's idiomatic key-based reset: the range view is keyed on its committed bounds in the Calendar dispatcher, so a newly applied range remounts it with fresh draft state. Cleaner and fully encapsulated — consumers need no special handling. Move the rationale into TSDoc (no inline comment).
1 parent ed21a26 commit 520aa22

1 file changed

Lines changed: 13 additions & 21 deletions

File tree

apps/sim/components/emcn/components/calendar/calendar.tsx

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,10 @@ export type CalendarProps = CalendarSingleProps | CalendarRangeProps
196196
*
197197
* `mode='single'` (default) commits on day click via `onChange`. `mode='range'`
198198
* stages a start/end selection behind Clear/Cancel/Apply actions (with optional
199-
* time-of-day inputs) and commits via `onRangeChange`.
199+
* time-of-day inputs) and commits via `onRangeChange`. The range view is keyed
200+
* on its committed bounds so a newly applied range remounts it with fresh draft
201+
* state (React's "reset all state with a key") — the staged start/end never
202+
* lingers when the source range changes.
200203
*
201204
* @example
202205
* <Calendar value={value} onChange={setValue} />
@@ -205,7 +208,14 @@ export type CalendarProps = CalendarSingleProps | CalendarRangeProps
205208
* <Calendar mode='range' startDate={from} endDate={to} showTime onRangeChange={apply} />
206209
*/
207210
export function Calendar(props: CalendarProps) {
208-
if (props.mode === 'range') return <RangeCalendarView {...props} />
211+
if (props.mode === 'range') {
212+
return (
213+
<RangeCalendarView
214+
key={`${String(props.startDate ?? '')}|${String(props.endDate ?? '')}`}
215+
{...props}
216+
/>
217+
)
218+
}
209219
return <SingleCalendarView {...props} />
210220
}
211221

@@ -346,32 +356,14 @@ function RangeCalendarView({
346356
className,
347357
}: CalendarRangeProps) {
348358
const seededStart = useMemo(() => parseDateValue(startDate), [startDate])
349-
const { today, view, setView, goToPrevMonth, goToNextMonth, cells } = useCalendarView(seededStart)
359+
const { today, view, goToPrevMonth, goToNextMonth, cells } = useCalendarView(seededStart)
350360

351361
const [rangeStart, setRangeStart] = useState<Date | null>(seededStart)
352362
const [rangeEnd, setRangeEnd] = useState<Date | null>(() => parseDateValue(endDate))
353363
const [selectingEnd, setSelectingEnd] = useState(false)
354364
const [startTime, setStartTime] = useState(() => extractTime(startDate, DEFAULT_RANGE_START_TIME))
355365
const [endTime, setEndTime] = useState(() => extractTime(endDate, DEFAULT_RANGE_END_TIME))
356366

357-
/**
358-
* Resync the staged selection when the bound props change (e.g. a new range
359-
* applied elsewhere) so the grid never lingers on a stale draft. Closing the
360-
* popover unmounts this view, so a fresh open already re-seeds from props;
361-
* this render-phase reset covers prop changes while it stays mounted.
362-
*/
363-
const seedKey = `${seededStart?.getTime() ?? ''}|${parseDateValue(endDate)?.getTime() ?? ''}|${extractTime(startDate, DEFAULT_RANGE_START_TIME)}|${extractTime(endDate, DEFAULT_RANGE_END_TIME)}`
364-
const [prevSeedKey, setPrevSeedKey] = useState(seedKey)
365-
if (seedKey !== prevSeedKey) {
366-
setPrevSeedKey(seedKey)
367-
setRangeStart(seededStart)
368-
setRangeEnd(parseDateValue(endDate))
369-
setSelectingEnd(false)
370-
setStartTime(extractTime(startDate, DEFAULT_RANGE_START_TIME))
371-
setEndTime(extractTime(endDate, DEFAULT_RANGE_END_TIME))
372-
if (seededStart) setView({ month: seededStart.getMonth(), year: seededStart.getFullYear() })
373-
}
374-
375367
const pickDay = (day: number) => {
376368
const date = new Date(view.year, view.month, day)
377369
if (!selectingEnd || !rangeStart) {

0 commit comments

Comments
 (0)