Skip to content

Commit

Permalink
move all view logic handling to useViews
Browse files Browse the repository at this point in the history
  • Loading branch information
joakbjerk authored and tujoworker committed Nov 7, 2024
1 parent 80d7a63 commit 41bf2cc
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export type DatePickerAddonProps = React.HTMLProps<HTMLElement> & {
function DatePickerAddon(props: DatePickerAddonProps) {
const {
updateDates,
forceViewMonthChange,
callOnChangeHandler,
hidePicker,
startDate,
Expand Down Expand Up @@ -54,14 +55,15 @@ function DatePickerAddon(props: DatePickerAddonProps) {
endDate?: Date
event?: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>
} = {}) => {
updateDates({ startDate, endDate }, undefined, true)
updateDates({ startDate, endDate })
forceViewMonthChange()
callOnChangeHandler({
startDate,
endDate: endDate || startDate,
event,
})
},
[updateDates, callOnChangeHandler]
[updateDates, callOnChangeHandler, forceViewMonthChange]
)

const setDate = useCallback(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ function DatePickerCalendar(restOfProps: DatePickerCalendarProps) {

const {
updateDates,
forceViewMonthChange,
startDate,
endDate,
hoverDate,
Expand Down Expand Up @@ -430,19 +431,17 @@ function DatePickerCalendar(restOfProps: DatePickerCalendarProps) {
}
}

updateDates(
dates,
() => {
// call after state update, so the input get's the latest state as well
callOnSelect({
event,
nr,
hidePicker: false,
...dates,
})
},
true
)
updateDates(dates, () => {
// call after state update, so the input get's the latest state as well
callOnSelect({
event,
nr,
hidePicker: false,
...dates,
})
})

forceViewMonthChange()

// and set the focus back again
if (listRef && listRef.current) {
Expand All @@ -464,6 +463,7 @@ function DatePickerCalendar(restOfProps: DatePickerCalendarProps) {
onlyMonth,
endMonth,
startMonth,
forceViewMonthChange,
]
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ export type DatePickerContextValues = ContextProps &
hasHadValidDate: boolean
updateDates: (
dates: DatePickerDates,
callback?: (dates: DatePickerDates) => void,
isTriggeredByShortcut?: boolean
callback?: (dates: DatePickerDates) => void
) => void
setState?: (state: DatePickerProviderState) => void
setViews: (views: Array<CalendarView>, callback?: () => void) => void
forceViewMonthChange: () => void
callOnChangeHandler: <E>(event: DatePickerChangeEvent<E>) => void
hidePicker: (event: DisplayPickerEvent) => void
previousDates: DatePickerDateProps
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { correctV1Format, isDisabled } from './DatePickerCalc'
import DatePickerContext, {
DatePickerContextValues,
} from './DatePickerContext'
import { CalendarView } from './hooks/useViews'
import useViews, { CalendarView } from './hooks/useViews'
import useDates, { DatePickerDates } from './hooks/useDates'
import useLastEventCallCache, {
LastEventCallCache,
Expand Down Expand Up @@ -88,14 +88,7 @@ function DatePickerProvider(externalProps: DatePickerProviderProps) {

const sharedContext = useContext(SharedContext)

const {
dates,
updateDates,
hasHadValidDate,
previousDates,
views,
setViews,
} = useDates(
const { dates, updateDates, hasHadValidDate, previousDates } = useDates(
{
date: date,
startDate: start_date,
Expand All @@ -112,6 +105,12 @@ function DatePickerProvider(externalProps: DatePickerProviderProps) {
}
)

const { views, setViews, forceViewMonthChange } = useViews({
startMonth: dates.startMonth,
endMonth: dates.endMonth,
isRange: range,
})

const [lastEventCallCache, setLastEventCallCache] =
useLastEventCallCache({
startDate: dates.startDate,
Expand Down Expand Up @@ -217,7 +216,6 @@ function DatePickerProvider(externalProps: DatePickerProviderProps) {
<DatePickerContext.Provider
value={{
translation: sharedContext.translation,
setViews,
updateDates,
getReturnObject,
callOnChangeHandler,
Expand All @@ -227,6 +225,8 @@ function DatePickerProvider(externalProps: DatePickerProviderProps) {
previousDates,
hasHadValidDate,
views,
setViews,
forceViewMonthChange,
}}
>
{children}
Expand Down
47 changes: 8 additions & 39 deletions packages/dnb-eufemia/src/components/date-picker/hooks/useDates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { convertStringToDate, isDisabled } from '../DatePickerCalc'
import isValid from 'date-fns/isValid'
import format from 'date-fns/format'
import { addMonths } from 'date-fns'
import useViews, { CalendarView } from './useViews'

export type DatePickerDateProps = {
date?: Date | string
Expand Down Expand Up @@ -82,25 +81,12 @@ export default function useDates(
setPreviousDates(dateProps)
}

// calling views here instead of DatePickerProvider, to able to sync start and end months up with calendar views
// TODO: Reduce to just use start/endDate or start/endMonth to reduce complexity,
// or only have startMonth and endMonth as props and not a state that changes
const [views, setViews] = useViews({
startMonth: dates.startMonth,
startDate: dates.startDate,
endDate: dates.endDate,
endMonth: dates.endMonth,
isRange,
})

const hasHadValidDate = useRef<boolean>(false)

// TODO: Update parameter to be an object, to improve readability
const updateDates = useCallback(
(
newDates: DatePickerDates,
callback?: (dates: DatePickerDates) => void,
forceMonthChange?: boolean
callback?: (dates: DatePickerDates) => void
) => {
// Correct dates based on min and max date
const correctedDates = shouldCorrectDate
Expand All @@ -117,9 +103,6 @@ export default function useDates(
const months = updateMonths({
newDates,
currentDates: dates,
views,
isRange,
forceMonthChange,
})

setDates((currentDates) => {
Expand All @@ -138,7 +121,7 @@ export default function useDates(
...correctedDates,
})
},
[dates, shouldCorrectDate, isRange, views]
[dates, shouldCorrectDate, isRange]
)

// Updated input dates based on start and end dates, move to DatePickerInput
Expand All @@ -163,8 +146,6 @@ export default function useDates(
updateDates,
hasHadValidDate: hasHadValidDate.current,
previousDates,
views,
setViews,
} as const
}

Expand Down Expand Up @@ -306,30 +287,18 @@ function correctDates({
function updateMonths({
newDates,
currentDates,
views,
isRange,
forceMonthChange,
}: {
newDates: DatePickerDates
currentDates: DatePickerDates
views: Array<CalendarView>
isRange: boolean
forceMonthChange: boolean
}) {
let startMonth = newDates.startMonth ?? newDates.startDate
let endMonth = newDates.endMonth ?? newDates.endDate
const [startView, endView] = views

// Make sure start and end months are synced up with calendar in range mode, and prevent both pickers showing the same month if start and end date are selected to be the same
if (isRange && !forceMonthChange) {
// If start and end date is the same day, but changed from the previous selected months
startMonth = startView?.month
endMonth = endView?.month
}
const startMonth =
newDates.startMonth ?? newDates.startDate ?? currentDates.startMonth
const endMonth =
newDates.endMonth ?? newDates.endDate ?? currentDates.endMonth

return {
startMonth: startMonth ?? currentDates.startMonth,
endMonth: endMonth ?? currentDates.endMonth,
startMonth,
endMonth,
}
}

Expand Down
37 changes: 26 additions & 11 deletions packages/dnb-eufemia/src/components/date-picker/hooks/useViews.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import addMonths from 'date-fns/addMonths'
import { useMemo, useState } from 'react'
import { useMemo, useRef, useState } from 'react'
import { DatePickerDates } from './useDates'

export type CalendarView = { nr: number; month?: Date }

export type ViewDates = {
startDate?: DatePickerDates['startDate']
endDate?: DatePickerDates['endDate']
startMonth?: DatePickerDates['startMonth']
endMonth?: DatePickerDates['endMonth']
}
Expand All @@ -21,6 +19,8 @@ export default function useViews({ isRange, ...dates }: UseViewsParams) {
getViews({ views: undefined, ...dates, isRange })
)

const forceViewChange = useRef(false)

const hasDateChanges = useMemo(
() =>
Object.keys(dates).some(
Expand All @@ -35,7 +35,13 @@ export default function useViews({ isRange, ...dates }: UseViewsParams) {
? views
: views[0]
: views
setViews(getViews({ ...dates, views: currentViews, isRange }))

// Maintain range views unless forced to change by shortcut or keyboard navigation
if (forceViewChange.current || !isRange) {
setViews(getViews({ ...dates, views: currentViews, isRange }))
forceViewChange.current = false
}

setPreviousDates(dates)
}

Expand All @@ -47,7 +53,15 @@ export default function useViews({ isRange, ...dates }: UseViewsParams) {
cb?.()
}

return [views, updateViews] as const
function forceViewMonthChange() {
forceViewChange.current = true
}

return {
views,
setViews: updateViews,
forceViewMonthChange,
} as const
}

export function getViews({
Expand All @@ -74,18 +88,19 @@ export function getViews({
}

function getMonthView(
{ startDate, endDate, startMonth, endMonth }: ViewDates,
{ startMonth, endMonth }: ViewDates,
nr: CalendarView['nr']
) {
if ((startMonth || startDate) && nr === 0) {
return startMonth || startDate
if (startMonth && nr === 0) {
return startMonth
}
if ((endMonth || endDate) && nr === 1) {
return endMonth || endDate

if (endMonth && nr === 1) {
return endMonth
}

// Here we add that default offset to every new calendar added,
// the first will get 0, the next one 1, and so forth
const fallbackMonth = startMonth || startDate || new Date()
const fallbackMonth = startMonth || new Date()
return addMonths(fallbackMonth, nr)
}

0 comments on commit 41bf2cc

Please sign in to comment.