Skip to content

Commit

Permalink
[pickers] Always use the same timezone in the field, the view and the…
Browse files Browse the repository at this point in the history
… layout components (#13481)
  • Loading branch information
flaviendelangle authored Jun 14, 2024
1 parent 6b2b815 commit 959c9b4
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import * as React from 'react';
import { screen } from '@mui/internal-test-utils';
import { describeAdapters } from 'test/utils/pickers';
import { MobileTimePicker } from '@mui/x-date-pickers/MobileTimePicker';
import { expect } from 'chai';

describe('<MobileTimePicker /> - Timezone', () => {
describeAdapters('Timezone prop', MobileTimePicker, ({ adapter, render }) => {
if (!adapter.isTimezoneCompatible) {
return;
}

it('should use the timezone prop for the value displayed in the toolbar', () => {
render(
<MobileTimePicker
timezone="America/New_York"
value={adapter.date('2022-04-17T15:30', 'default')}
open
/>,
);

expect(screen.getByMuiTest('hours')).to.have.text('11');
});
});
});
6 changes: 0 additions & 6 deletions packages/x-date-pickers/src/PickersLayout/usePickerLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ const usePickerLayout = <
const classes = useUtilityClasses(props);

// Action bar

const ActionBar = slots?.actionBar ?? PickersActionBar;
const actionBarProps = useSlotProps({
elementType: ActionBar,
Expand All @@ -93,7 +92,6 @@ const usePickerLayout = <
const actionBar = <ActionBar {...actionBarProps} />;

// Toolbar

const Toolbar = slots?.toolbar;
const toolbarProps = useSlotProps({
elementType: Toolbar!,
Expand All @@ -114,19 +112,16 @@ const usePickerLayout = <
const toolbar = toolbarHasView(toolbarProps) && !!Toolbar ? <Toolbar {...toolbarProps} /> : null;

// Content

const content = children;

// Tabs

const Tabs = slots?.tabs;
const tabs =
view && Tabs ? (
<Tabs view={view} onViewChange={onViewChange} className={classes.tabs} {...slotProps?.tabs} />
) : null;

// Shortcuts

const Shortcuts = slots?.shortcuts ?? PickersShortcuts;
const shortcutsProps = useSlotProps({
elementType: Shortcuts!,
Expand All @@ -144,7 +139,6 @@ const usePickerLayout = <
wrapperVariant,
},
});

const shortcuts = view && !!Shortcuts ? <Shortcuts {...shortcutsProps} /> : null;

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,19 +165,19 @@ export const usePickerValue = <
const {
onAccept,
onChange,
value: inValue,
value: inValueWithoutRenderTimezone,
defaultValue: inDefaultValue,
closeOnSelect = wrapperVariant === 'desktop',
timezone: timezoneProp,
} = props;

const { current: defaultValue } = React.useRef(inDefaultValue);
const { current: isControlled } = React.useRef(inValue !== undefined);
const { current: isControlled } = React.useRef(inValueWithoutRenderTimezone !== undefined);

/* eslint-disable react-hooks/rules-of-hooks, react-hooks/exhaustive-deps */
if (process.env.NODE_ENV !== 'production') {
React.useEffect(() => {
if (isControlled !== (inValue !== undefined)) {
if (isControlled !== (inValueWithoutRenderTimezone !== undefined)) {
console.error(
[
`MUI X: A component is changing the ${
Expand All @@ -191,7 +191,7 @@ export const usePickerValue = <
].join('\n'),
);
}
}, [inValue]);
}, [inValueWithoutRenderTimezone]);

React.useEffect(() => {
if (!isControlled && defaultValue !== inDefaultValue) {
Expand All @@ -208,13 +208,24 @@ export const usePickerValue = <

const utils = useUtils<TDate>();
const adapter = useLocalizationContext<TDate>();

const { isOpen, setIsOpen } = useOpenState(props);

const {
timezone,
value: inValueWithTimezoneToRender,
handleValueChange,
} = useValueWithTimezone({
timezone: timezoneProp,
value: inValueWithoutRenderTimezone,
defaultValue,
onChange,
valueManager,
});

const [dateState, setDateState] = React.useState<UsePickerValueState<TValue>>(() => {
let initialValue: TValue;
if (inValue !== undefined) {
initialValue = inValue;
if (inValueWithTimezoneToRender !== undefined) {
initialValue = inValueWithTimezoneToRender;
} else if (defaultValue !== undefined) {
initialValue = defaultValue;
} else {
Expand All @@ -225,19 +236,11 @@ export const usePickerValue = <
draft: initialValue,
lastPublishedValue: initialValue,
lastCommittedValue: initialValue,
lastControlledValue: inValue,
lastControlledValue: inValueWithTimezoneToRender,
hasBeenModifiedSinceMount: false,
};
});

const { timezone, handleValueChange } = useValueWithTimezone({
timezone: timezoneProp,
value: inValue,
defaultValue,
onChange,
valueManager,
});

useValidation(
{ ...props, value: dateState.draft, timezone },
validator,
Expand Down Expand Up @@ -297,21 +300,29 @@ export const usePickerValue = <
});

if (
inValue !== undefined &&
inValueWithTimezoneToRender !== undefined &&
(dateState.lastControlledValue === undefined ||
!valueManager.areValuesEqual(utils, dateState.lastControlledValue, inValue))
!valueManager.areValuesEqual(
utils,
dateState.lastControlledValue,
inValueWithTimezoneToRender,
))
) {
const isUpdateComingFromPicker = valueManager.areValuesEqual(utils, dateState.draft, inValue);
const isUpdateComingFromPicker = valueManager.areValuesEqual(
utils,
dateState.draft,
inValueWithTimezoneToRender,
);

setDateState((prev) => ({
...prev,
lastControlledValue: inValue,
lastControlledValue: inValueWithTimezoneToRender,
...(isUpdateComingFromPicker
? {}
: {
lastCommittedValue: inValue,
lastPublishedValue: inValue,
draft: inValue,
lastCommittedValue: inValueWithTimezoneToRender,
lastPublishedValue: inValueWithTimezoneToRender,
draft: inValueWithTimezoneToRender,
hasBeenModifiedSinceMount: true,
}),
}));
Expand Down

0 comments on commit 959c9b4

Please sign in to comment.