🐛(react) fix calendar selects initialization and syncing

Select under the calendar component were not properly initialized,
leading to issues. Additionally, syncing the dropdowns with the calendar
state was causing unnecessary renders. Selects now update on user events
triggered by the toggle button, ensuring the selected item remains
up-to-date. The code has been refactored to eliminate duplication
and improve the component's readability and maintainability.
This commit is contained in:
Lebaud Antoine
2023-06-14 14:02:40 +02:00
committed by aleb_the_flash
parent 10fa71e2a7
commit 76ad5621c6
2 changed files with 45 additions and 57 deletions

View File

@@ -0,0 +1,5 @@
---
"@openfun/cunningham-react": patch
---
Fix initial focused item on select opening under the calendar

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useMemo, useRef } from "react";
import React, { useMemo, useRef } from "react";
import {
CalendarDate,
createCalendar,
@@ -127,17 +127,6 @@ export const Calendar = ({
});
}, [state.maxValue, state.minValue, state.focusedDate.year]);
const downshiftMonth = useSelect({
items: monthItems,
itemToString: optionToString,
onSelectedItemChange: (e: UseSelectStateChange<Option>) => {
const updatedFocusedDate = state.focusedDate.set({
month: e?.selectedItem?.value,
});
state.setFocusedDate(updatedFocusedDate);
},
});
const yearItems: Array<Option> = useMemo(() => {
const calendarCurrentUser = createCalendar(
new Intl.DateTimeFormat().resolvedOptions().calendar
@@ -162,44 +151,24 @@ export const Calendar = ({
});
}, [state.focusedDate, state.timeZone, state.maxValue, state.minValue]);
const downshiftYear = useSelect({
items: yearItems,
itemToString: optionToString,
onSelectedItemChange: (e: UseSelectStateChange<Option>) => {
const updatedFocusedDate = state.focusedDate.set({
year: e?.selectedItem?.value,
});
state.setFocusedDate(updatedFocusedDate);
},
initialSelectedItem: yearItems.find(
(item) => item.value === state.focusedDate.year
),
});
useEffect(() => {
if (downshiftMonth.selectedItem?.value === state.focusedDate.month) {
return;
}
const focusedMonth = monthItems.find(
(item) => item.value === state.focusedDate.month
);
if (focusedMonth) {
downshiftMonth.selectItem(focusedMonth);
}
}, [state.focusedDate.month]);
useEffect(() => {
if (downshiftYear.selectedItem?.value === state.focusedDate.year) {
return;
}
const focusedYear = yearItems.find(
(item) => item.value === state.focusedDate.year
);
if (focusedYear) {
downshiftYear.selectItem(focusedYear);
}
}, [state.focusedDate.year]);
const { t } = useCunningham();
const useDownshiftSelect = (
key: string,
items: Array<Option>
): UseSelectReturnValue<Option> => {
return useSelect({
items,
itemToString: optionToString,
onSelectedItemChange: (e: UseSelectStateChange<Option>) => {
const updatedFocusedDate = state.focusedDate.set({
[key]: e?.selectedItem?.value,
});
state.setFocusedDate(updatedFocusedDate);
},
});
};
const downshiftMonth = useDownshiftSelect("month", monthItems);
const downshiftYear = useDownshiftSelect("year", yearItems);
// isDisabled and onPress props don't exist on the <Button /> component.
// remove them to avoid any warning.
@@ -214,6 +183,26 @@ export const Calendar = ({
...nextButtonOtherProps
} = nextButtonProps;
const getToggleButtonProps = (
key: string,
items: Array<Option>,
downshift: UseSelectReturnValue<Option>
) => ({
...downshift.getToggleButtonProps(),
onClick: () => {
const selectedItem = items.find(
(item) => item.value === state.focusedDate[key as keyof CalendarDate]
);
if (selectedItem) {
downshift.selectItem(selectedItem);
}
downshift.toggleMenu();
},
"aria-label": t(
`components.forms.date_picker.${key}_select_button_aria_label`
),
});
return (
<div className="c__calendar">
<div
@@ -245,10 +234,7 @@ export const Calendar = ({
size="small"
iconPosition="right"
icon={<span className="material-icons">arrow_drop_down</span>}
{...downshiftMonth.getToggleButtonProps()}
aria-label={t(
"components.forms.date_picker.month_select_button_aria_label"
)}
{...getToggleButtonProps("month", monthItems, downshiftMonth)}
>
{selectedMonthItemFormatter.format(
state.focusedDate.toDate(state.timeZone)
@@ -288,10 +274,7 @@ export const Calendar = ({
size="small"
iconPosition="right"
icon={<span className="material-icons">arrow_drop_down</span>}
{...downshiftYear.getToggleButtonProps()}
aria-label={t(
"components.forms.date_picker.year_select_button_aria_label"
)}
{...getToggleButtonProps("year", yearItems, downshiftYear)}
>
{yearItemsFormatter.format(
state.focusedDate.toDate(state.timeZone)