Skip to content

Commit

Permalink
Cut 965 date time input default time (#2725)
Browse files Browse the repository at this point in the history
* feat(dateTimeInput): init default time prop

* chore(date-time-input): add test

* chore(date-time-input): add comment to component

* chore(date-time-field): remove unnecessary test

* chore: add changeset

* chore(date-time-input): adjust typing

* fix(date-time-input): test

* chore: add review suggestion

* fix(date-time-input): remove timezone from default time formatting

* chore(date-time-input): review items

* chore(date-time-input): add extra test case

* chore(date-time-input): remove uneccessary async in test

* chore(date-time-input): review items

---------

Co-authored-by: Carlos Cortizas <97907068+CarlosCortizasCT@users.noreply.github.com>
  • Loading branch information
leventekobor and CarlosCortizasCT committed Feb 22, 2024
1 parent a21e7ae commit 75fcd4f
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 46 deletions.
7 changes: 7 additions & 0 deletions .changeset/tricky-cherries-behave.md
@@ -0,0 +1,7 @@
---
'@commercetools-uikit/date-time-field': minor
'@commercetools-uikit/date-time-input': minor
'@commercetools-uikit/calendar-time-utils': minor
---

We've included a new property in the `DateTimeInput` and `DateTimeField` components for consumers to be able to set the default time the calendar will show upon users opening it.
27 changes: 26 additions & 1 deletion packages/calendar-time-utils/src/calendar-time.spec.js
@@ -1,4 +1,13 @@
import { getLocalizedDateTimeFormatPattern } from './calendar-time';
import {
getLocalizedDateTimeFormatPattern,
formatDefaultTime,
} from './calendar-time';
import { warning } from '@commercetools-uikit/utils';

jest.mock('@commercetools-uikit/utils', () => ({
...jest.requireActual('@commercetools-uikit/utils'),
warning: jest.fn(),
}));

describe('getLocalizedDateTimeFormatPattern', () => {
const DATE_LOCALIZED_FORMATS = {
Expand Down Expand Up @@ -79,3 +88,19 @@ describe('getLocalizedDateTimeFormatPattern', () => {
});
});
});

describe('formatDefaultTime', () => {
it('should format the time', () => {
expect(formatDefaultTime('09:00', 'en')).toBe('9:00 AM');
expect(formatDefaultTime('13:00', 'en')).toBe('1:00 PM');
expect(formatDefaultTime('13:00', 'es')).toBe('13:00');
});

it('should return 12:00 AM for incorrect time format', () => {
expect(formatDefaultTime('1221', 'en')).toBe('12:00 AM');
expect(warning).toHaveBeenCalledWith(
false,
"DataTimeInput: the specified defaultDaySelectionTime '1221' is not supported. The format should be hh:mm, e.g. 11:10. Using 00:00 as default time."
);
});
});
24 changes: 23 additions & 1 deletion packages/calendar-time-utils/src/calendar-time.ts
Expand Up @@ -7,7 +7,7 @@ import moment, {
MomentInput,
LocaleSpecifier,
} from 'moment-timezone';
import { parseTime } from '@commercetools-uikit/utils';
import { parseTime, warning } from '@commercetools-uikit/utils';
import { DATE_FORMAT_LOCALIZED_MAPPINGS } from './formats';

type ParsedTime = {
Expand Down Expand Up @@ -43,6 +43,28 @@ export const changeTime = (
export const getPreviousDay = (day: MomentInput) =>
moment(day).subtract(1, 'day').format('YYYY-MM-DD');

export const formatDefaultTime = (time: string, locale: LocaleSpecifier) => {
const today = moment();
if (moment(time, 'HH:mm', true).isValid()) {
const [hour, minute] = time.split(':');
today.set({
hour: parseInt(hour, 10),
minute: parseInt(minute, 10),
});
return moment(today).locale(locale).format('LT'); // 5:13 PM
} else {
warning(
false,
`DataTimeInput: the specified defaultDaySelectionTime '${time}' is not supported. The format should be hh:mm, e.g. 11:10. Using 00:00 as default time.`
);
today.set({
hour: 0,
minute: 0,
});
return moment(today).locale(locale).format('LT'); // 12:00 AM
}
};

export const formatTime = (
day: MomentInput,
locale: LocaleSpecifier,
Expand Down
51 changes: 26 additions & 25 deletions packages/components/fields/date-time-field/README.md

Large diffs are not rendered by default.

Expand Up @@ -175,6 +175,10 @@ export type TDateTimeFieldProps = {
* Might be used to display additional information about the content of the field (E.g verified email)
*/
badge?: ReactNode;
/**
* The time that will be used by default when a user selects a calendar day
*/
defaultDaySelectionTime?: string;
};

type TDateTimeFieldState = Pick<TDateTimeFieldProps, 'id'>;
Expand Down Expand Up @@ -261,6 +265,7 @@ class DateTimeField extends Component<
{...filterDataAttributes(this.props)}
aria-invalid={hasError}
aria-errormessage={sequentialErrorsId}
defaultDaySelectionTime={this.props.defaultDaySelectionTime}
/>
<FieldErrors
id={sequentialErrorsId}
Expand Down
35 changes: 18 additions & 17 deletions packages/components/inputs/date-time-input/README.md
Expand Up @@ -48,23 +48,24 @@ export default Example;

## Properties

| Props | Type | Required | Default | Description |
| ---------------------- | -------------------------------------------------------------------------------------------- | :------: | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `aria-invalid` | `boolean` | | | Indicate if the value entered in the input is invalid. |
| `aria-errormessage` | `string` | | | HTML ID of an element containing an error message related to the input. |
| `horizontalConstraint` | `union`<br/>Possible values:<br/>`, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 'scale', 'auto'` | | | Horizontal size limit of the input field. |
| `value` | `string` || | The selected date, must either be an empty string or a date formatted in ISO 8601 (e.g. "2018-10-04T09:00:00.000Z"). |
| `onChange` | `Function`<br/>[See signature.](#signature-onChange) | | | Called when the date changes. Called with an event containing an empty string (no value) or a string in this format: "YYYY-MM-DD". |
| `onFocus` | `FocusEventHandler` | | | Called when the date input gains focus. |
| `onBlur` | `Function`<br/>[See signature.](#signature-onBlur) | | | Called when the date input loses focus. |
| `timeZone` | `string` || | Specifies the time zone in which the calendar and selected values are shown. It also influences how entered dates and times are parsed.&#xA;Get list of timezone with `moment.tz.names()` [See moment docs](https://momentjs.com/timezone/docs/#/data-loading/getting-zone-names/) |
| `id` | `string` | | | Used as the HTML `id` attribute. |
| `name` | `string` | | | Used as the HTML `name` attribute. |
| `placeholder` | `string` | | | Placeholder value to show in the input field |
| `isDisabled` | `boolean` | | | Disables the date picker |
| `isReadOnly` | `boolean` | | | Disables the date picker menu and sets the input field as read-only |
| `hasError` | `boolean` | | | Indicates the input field has an error |
| `hasWarning` | `boolean` | | | Indicates the input field has a warning |
| Props | Type | Required | Default | Description |
| ------------------------- | -------------------------------------------------------------------------------------------- | :------: | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `aria-invalid` | `boolean` | | | Indicate if the value entered in the input is invalid. |
| `aria-errormessage` | `string` | | | HTML ID of an element containing an error message related to the input. |
| `horizontalConstraint` | `union`<br/>Possible values:<br/>`, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 'scale', 'auto'` | | | Horizontal size limit of the input field. |
| `value` | `string` || | The selected date, must either be an empty string or a date formatted in ISO 8601 (e.g. "2018-10-04T09:00:00.000Z"). |
| `onChange` | `Function`<br/>[See signature.](#signature-onChange) | | | Called when the date changes. Called with an event containing an empty string (no value) or a string in this format: "YYYY-MM-DD". |
| `onFocus` | `FocusEventHandler` | | | Called when the date input gains focus. |
| `onBlur` | `Function`<br/>[See signature.](#signature-onBlur) | | | Called when the date input loses focus. |
| `timeZone` | `string` || | Specifies the time zone in which the calendar and selected values are shown. It also influences how entered dates and times are parsed.&#xA;Get list of timezone with `moment.tz.names()` [See moment docs](https://momentjs.com/timezone/docs/#/data-loading/getting-zone-names/) |
| `id` | `string` | | | Used as the HTML `id` attribute. |
| `name` | `string` | | | Used as the HTML `name` attribute. |
| `placeholder` | `string` | | | Placeholder value to show in the input field |
| `isDisabled` | `boolean` | | | Disables the date picker |
| `isReadOnly` | `boolean` | | | Disables the date picker menu and sets the input field as read-only |
| `hasError` | `boolean` | | | Indicates the input field has an error |
| `hasWarning` | `boolean` | | | Indicates the input field has a warning |
| `defaultDaySelectionTime` | `string` | | | The time that will be used by default when a user selects a calendar day. It must follow the “HH:mm” pattern (eg: 04:30, 13:25, 23:59) |

## Signatures

Expand Down
Expand Up @@ -178,3 +178,14 @@ describe('date picker keyboard navigation', () => {
expect(screen.getByText('August')).toBeInTheDocument();
});
});

describe('date picker defaultDaySelectionTime prop', () => {
it('should set the time prop when it is set', () => {
renderDateTimeInput({ defaultDaySelectionTime: '11:10' });
const dateInput = screen.getByLabelText('Date');

fireEvent.click(dateInput);

expect(screen.getByDisplayValue('11:10 AM')).toBeInTheDocument();
});
});

0 comments on commit 75fcd4f

Please sign in to comment.