Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: TimePicker – support replacement & removal by full selection #33344

Merged
merged 17 commits into from
Jan 2, 2024
Merged
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 71 additions & 50 deletions src/components/TimePicker/TimePicker.js
paultsimura marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -114,27 +114,41 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
[hours, minute, amPmValue, defaultValue],
);

const resetHours = () => {
setHours('00');
setSelectionHour({start: 0, end: 0});
};

const resetMinutes = () => {
setMinute('00');
setSelectionMinute({start: 0, end: 0});
focusHourInputOnLastCharacter();
paultsimura marked this conversation as resolved.
Show resolved Hide resolved
};

// This function receive value from hour input and validate it
// The valid format is HH(from 00 to 12). If the user input 9, it will be 09. If user try to change 09 to 19 it would skip the first character
const handleHourChange = (text) => {
paultsimura marked this conversation as resolved.
Show resolved Hide resolved
if (_.isEmpty(text)) {
resetHours();
return;
}

const isOnlyNumericValue = /^\d+$/.test(text.trim());
// Skip if the user is pasting the text or use non numeric characters.
if (selectionHour.start !== selectionHour.end || !isOnlyNumericValue) {
if (!isOnlyNumericValue) {
return;
}

// Remove non-numeric characters.
const filteredText = text.replace(/[^0-9]/g, '');

let newHour = hours;
let newSelection = selectionHour.start;

// Case when the cursor is at the start.
if (selectionHour.start === 0) {
// Handle cases where the hour would be > 12.

// when you entering text the filteredText would consist of three numbers
if (selectionHour.start === 0 && selectionHour.end === 0) {
// When the user is entering text, the filteredText consists of three numbers
const formattedText = `${filteredText[0]}${filteredText[2] || 0}`;
if (formattedText > 12 && formattedText <= 24) {
// The hour is between 12 and 24 – switch AM to PM.
newHour = String(formattedText - 12).padStart(2, '0');
newSelection = 2;
setAmPmValue(CONST.TIME_PERIOD.PM);
Expand All @@ -145,35 +159,37 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
newHour = `${formattedText[0]}${formattedText[1]}`;
newSelection = 1;
}
} else if (selectionHour.start === 1) {
// Case when the cursor is at the second position.
} else if (selectionHour.start === 1 && selectionHour.end === 1) {
// The cursor is at the second position.
const formattedText = `${filteredText[0]}${filteredText[1]}`;

if (filteredText.length < 2) {
// If we remove a value, prepend 0.
newHour = `0${text}`;
newHour = `0${filteredText}`;
newSelection = 0;
// If the second digit is > 2, replace the hour with 0 and the second digit.
} else if (formattedText > 12 && formattedText <= 24) {
newHour = String(formattedText - 12).padStart(2, '0');
newSelection = 2;
setAmPmValue(CONST.TIME_PERIOD.PM);
} else if (formattedText > 24) {
newHour = `0${text[1]}`;
newHour = `0${filteredText[1]}`;
newSelection = 2;
} else {
newHour = `${text[0]}${text[1]}`;
newHour = `${filteredText[0]}${filteredText[1]}`;
setHours(newHour);
newSelection = 2;
}
} else if (selectionHour.start === 2 && selectionHour.end === 2) {
// Case when the cursor is at the end and no text is selected.
if (filteredText.length < 2) {
newHour = `${text}0`;
newSelection = 1;
} else {
newSelection = 2;
}
} else if (filteredText.length <= 1 && filteredText < 2) {
newHour = `${filteredText}0`;
newSelection = 1;
} else if (filteredText > 12 && filteredText <= 24) {
newHour = String(filteredText - 12).padStart(2, '0');
newSelection = 2;
setAmPmValue(CONST.TIME_PERIOD.PM);
} else if (filteredText.length <= 2) {
newHour = String(Math.min(filteredText, 12)).padStart(2, '0');
newSelection = 2;
}
paultsimura marked this conversation as resolved.
Show resolved Hide resolved

setHours(newHour);
Expand All @@ -186,9 +202,13 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
// This function receive value from minute input and validate it
// The valid format is MM(from 00 to 59). If the user input 9, it will be 09. If user try to change 09 to 99 it would skip the character
const handleMinutesChange = (text) => {
if (_.isEmpty(text)) {
resetMinutes();
return;
}

const isOnlyNumericValue = /^\d+$/.test(text.trim());
// Skip if the user is pasting the text or use non numeric characters.
if (selectionMinute.start !== selectionMinute.end || !isOnlyNumericValue) {
if (!isOnlyNumericValue) {
return;
}

Expand All @@ -197,46 +217,35 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {

let newMinute = minute;
let newSelection = selectionMinute.start;
// Case when user selects and replaces the text.
if (selectionMinute.start !== selectionMinute.end) {
// If the first digit is > 5, prepend 0.
if (filteredText.length === 1 && filteredText > 5) {
newMinute = `0${filteredText}`;
newSelection = 2;
// If the first digit is <= 5, append 0 at the end.
} else if (filteredText.length === 1 && filteredText <= 5) {
newMinute = `${filteredText}0`;
newSelection = 1;
} else {
newMinute = `${filteredText.slice(0, 2)}`;
newSelection = 2;
}
} else if (selectionMinute.start === 0) {
// Case when the cursor is at the start.

if (selectionMinute.start === 0 && selectionMinute.end === 0) {
// The cursor is at the start.
const formattedText = `${filteredText[0]}${filteredText[2] || 0}`;
if (text[0] >= 6) {
if (filteredText[0] >= 6) {
newMinute = `0${formattedText[1]}`;
newSelection = 2;
} else {
newMinute = `${formattedText[0]}${formattedText[1]}`;
newSelection = 1;
}
} else if (selectionMinute.start === 1) {
// Case when the cursor is at the second position.
} else if (selectionMinute.start === 1 && selectionMinute.end === 1) {
// The cursor is at the second position.
// If we remove a value, prepend 0.
if (filteredText.length < 2) {
newMinute = `0${text}`;
newMinute = `0${filteredText}`;
newSelection = 0;
setSelectionHour({start: 2, end: 2});
hourInputRef.current.focus();
} else {
newMinute = `${text[0]}${text[1]}`;
newMinute = `${filteredText[0]}${filteredText[1]}`;
newSelection = 2;
}
} else if (filteredText.length < 2) {
// Case when the cursor is at the end and no text is selected.
newMinute = `${text}0`;
} else if (filteredText.length <= 1 && filteredText <= 5) {
newMinute = `${filteredText}0`;
newSelection = 1;
} else if (filteredText.length <= 2) {
newMinute = String(Math.min(filteredText, 59)).padStart(2, '0');
newSelection = 2;
}

setMinute(newMinute);
Expand All @@ -262,14 +271,25 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
}
if (key === '<' || key === 'Backspace') {
if (isHourFocused) {
if (selectionHour.start === 0 && selectionHour.end === 2) {
resetHours();
return;
}

const newHour = replaceWithZeroAtPosition(hours, selectionHour.start);
setHours(newHour);
setSelectionHour(decreaseBothSelectionByOne(selectionHour));
} else if (isMinuteFocused) {
if (selectionMinute.start === 0) {
if (selectionMinute.start === 0 && selectionMinute.end === 2) {
resetMinutes();
return;
}

if (selectionMinute.start === 0 && selectionMinute.end === 0) {
focusHourInputOnLastCharacter();
return;
}

const newMinute = replaceWithZeroAtPosition(minute, selectionMinute.start);
setMinute(newMinute);
setSelectionMinute(decreaseBothSelectionByOne(selectionMinute));
Expand Down Expand Up @@ -322,13 +342,14 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {

const handleFocusOnBackspace = useCallback(
(e) => {
if (selectionMinute.start !== 0 || e.key !== 'Backspace') {
if (selectionMinute.start !== 0 || selectionMinute.end !== 0 || e.key !== 'Backspace') {
return;
}
hourInputRef.current.focus();
e.preventDefault();
focusHourInputOnLastCharacter();
paultsimura marked this conversation as resolved.
Show resolved Hide resolved
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[selectionMinute.start],
[selectionMinute.start, selectionMinute.end, focusHourInputOnLastCharacter],
);

const {styleForAM, styleForPM} = StyleUtils.getStatusAMandPMButtonStyle(amPmValue);
Expand Down
Loading