diff --git a/packages/lib/src/time-input/TimeInput.stories.tsx b/packages/lib/src/time-input/TimeInput.stories.tsx index 6a295aa2c..9a8632bda 100644 --- a/packages/lib/src/time-input/TimeInput.stories.tsx +++ b/packages/lib/src/time-input/TimeInput.stories.tsx @@ -119,19 +119,10 @@ const TimePickerExamples = () => { <DxcContainer width="250px"> - <TimePicker onSelectMinutes={() => {}} onSelectHours={() => {}} timeFormat="24" id="testId" tabIndex={0} /> + <TimePicker onPickTime={() => {}} timeFormat="24" id="testId" tabIndex={0} /> + <TimePicker onPickTime={() => {}} timeFormat="24" id="testId" tabIndex={0} hourValue={15} minuteValue={30} /> <TimePicker - onSelectMinutes={() => {}} - onSelectHours={() => {}} - timeFormat="24" - id="testId" - tabIndex={0} - hourValue={15} - minuteValue={30} - /> - <TimePicker - onSelectMinutes={() => {}} - onSelectHours={() => {}} + onPickTime={() => {}} timeFormat="24" id="testId" tabIndex={0} @@ -145,10 +136,9 @@ const TimePickerExamples = () => { <ExampleContainer> <Title title="Time Picker 12h format" theme="light" level={3} /> <DxcContainer width="250px"> - <TimePicker onSelectMinutes={() => {}} onSelectHours={() => {}} timeFormat="12" id="testId" tabIndex={0} /> + <TimePicker onPickTime={() => {}} timeFormat="12" id="testId" tabIndex={0} /> <TimePicker - onSelectMinutes={() => {}} - onSelectHours={() => {}} + onPickTime={() => {}} timeFormat="12" id="testId" tabIndex={0} @@ -157,8 +147,7 @@ const TimePickerExamples = () => { dayPeriod={1} /> <TimePicker - onSelectMinutes={() => {}} - onSelectHours={() => {}} + onPickTime={() => {}} timeFormat="12" id="testId" tabIndex={0} @@ -173,10 +162,9 @@ const TimePickerExamples = () => { <ExampleContainer pseudoState={"pseudo-hover"}> <Title title="hover" theme="light" level={3} /> <DxcContainer width="250px"> - <TimePicker onSelectMinutes={() => {}} onSelectHours={() => {}} timeFormat="12" id="testId" tabIndex={0} /> + <TimePicker onPickTime={() => {}} timeFormat="12" id="testId" tabIndex={0} /> <TimePicker - onSelectMinutes={() => {}} - onSelectHours={() => {}} + onPickTime={() => {}} timeFormat="12" id="testId" tabIndex={0} @@ -185,8 +173,7 @@ const TimePickerExamples = () => { dayPeriod={1} /> <TimePicker - onSelectMinutes={() => {}} - onSelectHours={() => {}} + onPickTime={() => {}} timeFormat="12" id="testId" tabIndex={0} @@ -201,10 +188,9 @@ const TimePickerExamples = () => { <ExampleContainer pseudoState={"pseudo-focus"}> <Title title="focus" theme="light" level={3} /> <DxcContainer width="250px"> - <TimePicker onSelectMinutes={() => {}} onSelectHours={() => {}} timeFormat="12" id="testId" tabIndex={0} /> + <TimePicker onPickTime={() => {}} timeFormat="12" id="testId" tabIndex={0} /> <TimePicker - onSelectMinutes={() => {}} - onSelectHours={() => {}} + onPickTime={() => {}} timeFormat="12" id="testId" tabIndex={0} @@ -213,8 +199,7 @@ const TimePickerExamples = () => { dayPeriod={1} /> <TimePicker - onSelectMinutes={() => {}} - onSelectHours={() => {}} + onPickTime={() => {}} timeFormat="12" id="testId" tabIndex={0} @@ -229,10 +214,9 @@ const TimePickerExamples = () => { <ExampleContainer pseudoState={"pseudo-active"}> <Title title="active" theme="light" level={3} /> <DxcContainer width="250px"> - <TimePicker onSelectMinutes={() => {}} onSelectHours={() => {}} timeFormat="12" id="testId" tabIndex={0} /> + <TimePicker onPickTime={() => {}} timeFormat="12" id="testId" tabIndex={0} /> <TimePicker - onSelectMinutes={() => {}} - onSelectHours={() => {}} + onPickTime={() => {}} timeFormat="12" id="testId" tabIndex={0} @@ -241,8 +225,7 @@ const TimePickerExamples = () => { dayPeriod={1} /> <TimePicker - onSelectMinutes={() => {}} - onSelectHours={() => {}} + onPickTime={() => {}} timeFormat="12" id="testId" tabIndex={0} diff --git a/packages/lib/src/time-input/TimeInput.test.tsx b/packages/lib/src/time-input/TimeInput.test.tsx index 64c3569f5..b1c9451ca 100644 --- a/packages/lib/src/time-input/TimeInput.test.tsx +++ b/packages/lib/src/time-input/TimeInput.test.tsx @@ -110,13 +110,13 @@ describe("DxcTimeInput rendering", () => { expect(getByText("AM")).toBeTruthy(); const hourbutton = getAllByText("07"); if (hourbutton[0]) userEvent.click(hourbutton[0]); - expect(mockOnChange).toHaveBeenCalledWith("07: "); + expect(mockOnChange).toHaveBeenCalledWith("07:00 AM"); const minuteButton = getAllByText("30"); if (minuteButton[0]) userEvent.click(minuteButton[0]); - expect(mockOnChange).toHaveBeenCalledWith("07:30 "); - const amButton = getByText("AM"); + expect(mockOnChange).toHaveBeenCalledWith("07:30 AM"); + const amButton = getAllByText("AM")[0]; expect(amButton).toBeTruthy(); - userEvent.click(amButton); + if (amButton) userEvent.click(amButton); expect(mockOnChange).toHaveBeenCalledWith("07:30 AM"); }); @@ -130,14 +130,14 @@ describe("DxcTimeInput rendering", () => { userEvent.keyboard("{ArrowDown}"); userEvent.keyboard("{ArrowDown}"); userEvent.keyboard("{Enter}"); - expect(mockOnChange).toHaveBeenCalledWith("03: "); + expect(mockOnChange).toHaveBeenCalledWith("03:00 AM"); userEvent.tab(); userEvent.keyboard("{ArrowUp}"); userEvent.keyboard("{Enter}"); - expect(mockOnChange).toHaveBeenCalledWith("03:55 "); + expect(mockOnChange).toHaveBeenCalledWith("03:55 AM"); userEvent.keyboard("{ArrowDown}"); userEvent.keyboard(" "); - expect(mockOnChange).toHaveBeenCalledWith("03:00 "); + expect(mockOnChange).toHaveBeenCalledWith("03:00 AM"); userEvent.tab(); userEvent.keyboard("{ArrowDown}"); userEvent.keyboard("{Enter}"); diff --git a/packages/lib/src/time-input/TimeInput.tsx b/packages/lib/src/time-input/TimeInput.tsx index 01af3b9aa..d18a4310f 100644 --- a/packages/lib/src/time-input/TimeInput.tsx +++ b/packages/lib/src/time-input/TimeInput.tsx @@ -53,6 +53,8 @@ const ColonContainer = styled.span` color: var(--color-fg-neutral-dark); `; +const isNumber = (value: string) => /^\d{1,2}$/.test(value); + const DxcTimeInput = forwardRef<RefType, TimeInputPropsType>( ( { @@ -95,10 +97,10 @@ const DxcTimeInput = forwardRef<RefType, TimeInputPropsType>( if (time) { const numberPart = timeFormat === "12" ? time.split(" ")[0] : time; if (numberPart) { - const [hour, minute, second] = numberPart.split(":").map(Number); - setHourValue(hour || hour === 0 ? hour : undefined); - setMinuteValue(minute || minute === 0 ? minute : undefined); - setSecondValue(second || second === 0 ? second : undefined); + const [hourStr, minuteStr, secondStr] = numberPart.split(":"); + setHourValue(hourStr && isNumber(hourStr) ? Number(hourStr) : undefined); + setMinuteValue(minuteStr && isNumber(minuteStr) ? Number(minuteStr) : undefined); + setSecondValue(secondStr && isNumber(secondStr) ? Number(secondStr) : undefined); } if (timeFormat === "12" && time.includes(" ")) { const dayPeriodValue = time.split(" ")[1] === "AM" ? 0 : time.split(" ")[1] === "PM" ? 1 : undefined; @@ -343,44 +345,15 @@ const DxcTimeInput = forwardRef<RefType, TimeInputPropsType>( <DxcPopover popoverContent={ <TimePicker - onSelectHours={(value) => { - if (!isControlled) { - setHourValue(value); - } - if (typeof onChange === "function") { - onChange( - generateEventValue(value, minuteValue, secondValue, dayPeriodValue, showSeconds, timeFormat) - ); - } - }} - onSelectMinutes={(value) => { - if (!isControlled) { - setMinuteValue(value); - } - if (typeof onChange === "function") { - onChange( - generateEventValue(hourValue, value, secondValue, dayPeriodValue, showSeconds, timeFormat) - ); - } - }} - onSelectSeconds={(value) => { - if (!isControlled) { - setSecondValue(value); - } - if (typeof onChange === "function") { - onChange( - generateEventValue(hourValue, minuteValue, value, dayPeriodValue, showSeconds, timeFormat) - ); - } - }} - onSelectDayPeriod={(value: number) => { + onPickTime={(hour, minute, second, dayPeriod) => { if (!isControlled) { - setDayPeriodValue(value); + setDayPeriodValue(dayPeriod); + setSecondValue(second); + setMinuteValue(minute); + setHourValue(hour); } if (typeof onChange === "function") { - onChange( - generateEventValue(hourValue, minuteValue, secondValue, value, showSeconds, timeFormat) - ); + onChange(generateEventValue(hour, minute, second, dayPeriod, showSeconds, timeFormat)); } }} timeFormat={timeFormat} diff --git a/packages/lib/src/time-input/TimePicker.tsx b/packages/lib/src/time-input/TimePicker.tsx index 07f5f7fcf..5d43d71b8 100644 --- a/packages/lib/src/time-input/TimePicker.tsx +++ b/packages/lib/src/time-input/TimePicker.tsx @@ -3,7 +3,6 @@ import { TimePickerPropsType } from "./types"; import { useEffect, useState } from "react"; import TimePickerColumn from "./TimePickerColumn"; import { handleColumnKeyDown } from "./utils"; - // Array to be used in seconds and minutes. const STEP = 5; const ARRAY_OF_60 = Array.from({ length: 60 / STEP }, (_, index) => index * STEP); @@ -15,10 +14,7 @@ const TimePickerContainer = styled.div` `; const TimePicker = ({ - onSelectHours, - onSelectMinutes, - onSelectSeconds, - onSelectDayPeriod, + onPickTime, timeFormat, showSeconds, hourValue, @@ -28,12 +24,25 @@ const TimePicker = ({ id, tabIndex = 0, }: TimePickerPropsType) => { - const [hourToFocus, setHourToFocus] = useState(hourValue || 1); - const [minuteToFocus, setMinuteToFocus] = useState(minuteValue || 0); - const [secondToFocus, setSecondToFocus] = useState(secondValue || 0); - const [dayPeriodToFocus, setDayPeriodToFocus] = useState(dayPeriod || 0); + const [hourToFocus, setHourToFocus] = useState(hourValue ?? (timeFormat === "12" ? 1 : 0)); + const [minuteToFocus, setMinuteToFocus] = useState(minuteValue ?? 0); + const [secondToFocus, setSecondToFocus] = useState(secondValue ?? 0); + const [dayPeriodToFocus, setDayPeriodToFocus] = useState(dayPeriod ?? 0); const totalHours = timeFormat === "12" ? 12 : 24; + const onPickerSelect = (value: number, type: "hour" | "minute" | "second" | "dayPeriod") => { + const hourVal = type === "hour" ? value : (hourValue ?? (timeFormat === "12" ? 1 : 0)); + const minuteVal = type === "minute" ? value : (minuteValue ?? 0); + const secondVal = type === "second" ? value : (secondValue ?? 0); + const dayPeriodVal = type === "dayPeriod" ? value : (dayPeriod ?? 0); + + setDayPeriodToFocus(dayPeriodVal); + setSecondToFocus(secondVal); + setMinuteToFocus(minuteVal); + setHourToFocus(hourVal); + onPickTime(hourVal, minuteVal, secondVal, dayPeriodVal); + }; + useEffect(() => { if (dayPeriodToFocus !== undefined && id) { document.getElementById(`${id}-dayPeriod-${dayPeriodToFocus}`)?.focus(); @@ -65,11 +74,12 @@ const TimePicker = ({ tabIndex={tabIndex} dataType="hour" onClick={(value: number) => { - onSelectHours(value); - setHourToFocus(value); + onPickerSelect(value, "hour"); }} onKeyboardEvent={(event: React.KeyboardEvent, value: number) => - handleColumnKeyDown(event, "hour", value, totalHours, setHourToFocus, onSelectHours) + handleColumnKeyDown(event, "hour", value, totalHours, setHourToFocus, (value) => + onPickerSelect(value, "hour") + ) } /> <TimePickerColumn @@ -80,11 +90,18 @@ const TimePicker = ({ tabIndex={tabIndex} dataType="minute" onClick={(value: number) => { - onSelectMinutes(value); - setMinuteToFocus(value); + onPickerSelect(value, "minute"); }} onKeyboardEvent={(event: React.KeyboardEvent, value: number) => - handleColumnKeyDown(event, "minute", value, 60, setMinuteToFocus, onSelectMinutes, STEP) + handleColumnKeyDown( + event, + "minute", + value, + 60, + setMinuteToFocus, + (value) => onPickerSelect(value, "minute"), + STEP + ) } /> {showSeconds && ( @@ -96,13 +113,18 @@ const TimePicker = ({ tabIndex={tabIndex} dataType="second" onClick={(value: number) => { - if (typeof onSelectSeconds === "function") { - onSelectSeconds(value); - setSecondToFocus(value); - } + onPickerSelect(value, "second"); }} onKeyboardEvent={(event: React.KeyboardEvent, value: number) => - handleColumnKeyDown(event, "second", value, 60, setSecondToFocus, onSelectSeconds, STEP) + handleColumnKeyDown( + event, + "second", + value, + 60, + setSecondToFocus, + (value) => onPickerSelect(value, "second"), + STEP + ) } /> )} @@ -115,13 +137,12 @@ const TimePicker = ({ tabIndex={tabIndex} dataType="dayPeriod" onClick={(value: number) => { - if (typeof onSelectDayPeriod === "function") { - onSelectDayPeriod(value); - setDayPeriodToFocus(value); - } + onPickerSelect(value, "dayPeriod"); }} onKeyboardEvent={(event: React.KeyboardEvent, value: number) => - handleColumnKeyDown(event, "dayPeriod", value, 2, setDayPeriodToFocus, onSelectDayPeriod) + handleColumnKeyDown(event, "dayPeriod", value, 2, setDayPeriodToFocus, (value) => + onPickerSelect(value, "dayPeriod") + ) } /> )} diff --git a/packages/lib/src/time-input/types.ts b/packages/lib/src/time-input/types.ts index 1ec59e7a8..e10e787af 100644 --- a/packages/lib/src/time-input/types.ts +++ b/packages/lib/src/time-input/types.ts @@ -104,10 +104,7 @@ export type TimeSpinButtonPropsType = { }; export type TimePickerPropsType = { - onSelectHours: (hours: number) => void; - onSelectMinutes: (minutes: number) => void; - onSelectSeconds?: (seconds: number) => void; - onSelectDayPeriod?: (isPM: number) => void; + onPickTime: (hours: number, minutes: number, seconds?: number, dayPeriod?: number) => void; timeFormat: "12" | "24"; showSeconds?: boolean; hourValue?: number; diff --git a/packages/lib/src/time-input/utils.ts b/packages/lib/src/time-input/utils.ts index 7a23e110f..def5a10bf 100644 --- a/packages/lib/src/time-input/utils.ts +++ b/packages/lib/src/time-input/utils.ts @@ -69,7 +69,6 @@ export const handleKeyDown = ( rawInput.current = (rawInput.current + newDigit.current).slice(-maxValue.toString().length); newValue = resolveValue(rawInput.current, maxValue, minValue); // If the raw input has reached the max length or exceeds the max value with the new digit, consider it complete and move to the next field. - console.log("rawInput:", rawInput.current, "newDigit:", newDigit.current, "newValue:", newValue); if (checkCompletion(rawInput.current, maxValue)) { rawInput.current = pad(newValue); if (typeof onComplete === "function") {