Skip to content

Commit

Permalink
fix: datepicker clear issue on deleting one char from the middle
Browse files Browse the repository at this point in the history
affects: @medly-components/core, @medly-components/forms
  • Loading branch information
gmukul01 committed Jun 8, 2024
1 parent 9466675 commit 936577c
Show file tree
Hide file tree
Showing 10 changed files with 42 additions and 18 deletions.
10 changes: 10 additions & 0 deletions packages/core/src/components/DatePicker/DatePicker.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,16 @@ describe('DatePicker component', () => {
fireEvent.change(screen.getByRole('textbox'), { target: { value: '01 / 02' } });
expect(mockOnChange).toHaveBeenCalledWith(null);
});

it('should call onChange with null if we delete char from the middle', async () => {
const mockOnChange = jest.fn(),
dateToSelect = new Date(2020, 0, 2);
render(<DatePicker id="dob" value={null} displayFormat="MM/dd/yyyy" onChange={mockOnChange} />);
fireEvent.change(screen.getByRole('textbox'), { target: { value: '01 / 02 / 2020' } });
expect(mockOnChange).toHaveBeenCalledWith(dateToSelect);
fireEvent.change(screen.getByRole('textbox'), { target: { value: '01 / 0 / 2020' } });
expect(mockOnChange).toHaveBeenCalledWith(null);
});
});

describe('error messages', () => {
Expand Down
5 changes: 2 additions & 3 deletions packages/core/src/components/DatePicker/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const Component: FC<DatePickerProps> = memo(
() => (value instanceof Date ? value : typeof value === 'string' ? parseToDate(value, displayFormat!) : null),
[value, displayFormat]
);

const wrapperRef = useRef<HTMLDivElement>(null),
inputRef = useCombinedRefs<HTMLInputElement>(ref, useRef(null)),
[inputKey, setInputKey] = useState(0),
Expand All @@ -49,9 +50,7 @@ const Component: FC<DatePickerProps> = memo(
isErrorPresent = useMemo(() => !!errorText || !!builtInErrorMessage, [errorText, builtInErrorMessage]);

useEffect(() => {
if (date === null) {
setTextValue('');
} else if (date) {
if (date) {
setTextValue(format(date, displayFormat!).replace(new RegExp('\\/|\\-', 'g'), ' $& '));
}
}, [date, displayFormat]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ exports[`DatePicker component calendar icon should show calendar icon displayed
-ms-user-select: none;
user-select: none;
pointer-events: none;
white-space: pre-wrap;
color: rgba(0,90,238,.2);
top: 50%;
-webkit-transform: translateY(-50%);
Expand Down Expand Up @@ -572,6 +573,7 @@ exports[`DatePicker component calendar icon should show calendar icon displayed
-ms-user-select: none;
user-select: none;
pointer-events: none;
white-space: pre-wrap;
color: rgba(0,90,238,.2);
top: 50%;
-webkit-transform: translateY(-50%);
Expand Down Expand Up @@ -13428,6 +13430,7 @@ exports[`DatePicker component should render properly when hideInput prop is pass
-ms-user-select: none;
user-select: none;
pointer-events: none;
white-space: pre-wrap;
color: rgba(0,90,238,.2);
bottom: 0.7rem;
}
Expand Down Expand Up @@ -13827,6 +13830,7 @@ exports[`DatePicker component should render properly when value is of date type
-ms-user-select: none;
user-select: none;
pointer-events: none;
white-space: pre-wrap;
color: rgba(0,90,238,.2);
bottom: 0.7rem;
}
Expand Down Expand Up @@ -14207,6 +14211,7 @@ exports[`DatePicker component should render properly when value is of string typ
-ms-user-select: none;
user-select: none;
pointer-events: none;
white-space: pre-wrap;
color: rgba(0,90,238,.2);
top: 50%;
-webkit-transform: translateY(-50%);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ export const useDateRangeTextFieldsHandlers = (props: Props) => {
}, []),
handleTextChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const maskedValue = getMaskedValue(e, mask),
const { maskedValue, selectionStart } = getMaskedValue(e, mask),
parsedDate = parseToDate(e.target.value, displayFormat),
maskedLabel = `${maskedValue}${mask.substr(maskedValue.length)}`;

e.target.setSelectionRange(selectionStart, selectionStart);
if (e.target.name === 'START_DATE') {
setStartDateText(maskedValue);
setStartDateMaskLabel(maskedLabel);
Expand Down Expand Up @@ -101,8 +101,11 @@ export const useDateRangeTextFieldsHandlers = (props: Props) => {
validateOnWrapperBlur = useCallback(
(event: ChangeEvent<HTMLInputElement>) => {
const validatorMessage = (validator && validator(selectedDates, event)) || '',
customMessage = (required && !selectedDates.startDate && !selectedDates.endDate && 'Please fill in this field.') || '',
message = validator ? validatorMessage : customMessage;
customRequiredMessage =
required && (!selectedDates.startDate || !selectedDates.endDate) && 'Please fill in this field.',
customInvalidMessage =
(!isValidDate(selectedDates.startDate) || !isValidDate(selectedDates.endDate)) && 'Enter valid date',
message = validator ? validatorMessage : customRequiredMessage || customInvalidMessage || '';
setErrorMessage(message);
if (validator) {
startDateRef.current?.setCustomValidity(validatorMessage);
Expand All @@ -115,10 +118,10 @@ export const useDateRangeTextFieldsHandlers = (props: Props) => {
useEffect(() => {
const formattedStartDate = selectedDates.startDate ? getFormattedDate(selectedDates.startDate, displayFormat) : '',
formattedEndDate = selectedDates.endDate ? getFormattedDate(selectedDates.endDate, displayFormat) : '';
setStartDateText(formattedStartDate);
setEndDateText(formattedEndDate);
setStartDateMaskLabel(formattedStartDate || mask);
setEndDateMaskLabel(formattedEndDate || mask);
formattedStartDate && setStartDateText(formattedStartDate);
formattedEndDate && setEndDateText(formattedEndDate);
formattedStartDate && setStartDateMaskLabel(formattedStartDate || mask);
formattedEndDate && setEndDateMaskLabel(formattedEndDate || mask);
isValidDate(selectedDates.startDate) && isValidDate(selectedDates.endDate) && setErrorMessage('');
}, [isActive, selectedDates, displayFormat]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1901,6 +1901,7 @@ exports[`DateRangePicker Custom date range options should render properly with c
-ms-user-select: none;
user-select: none;
pointer-events: none;
white-space: pre-wrap;
color: rgba(0,90,238,.2);
bottom: 0.7rem;
}
Expand Down Expand Up @@ -24175,6 +24176,7 @@ exports[`DateRangePicker should render properly 1`] = `
-ms-user-select: none;
user-select: none;
pointer-events: none;
white-space: pre-wrap;
color: rgba(0,90,238,.2);
bottom: 0.7rem;
}
Expand Down Expand Up @@ -26424,6 +26426,7 @@ exports[`DateRangePicker should render properly with single month 1`] = `
-ms-user-select: none;
user-select: none;
pointer-events: none;
white-space: pre-wrap;
color: rgba(0,90,238,.2);
bottom: 0.7rem;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const MaskPlaceholder = styled('span')<{
cursor: text;
user-select: none;
pointer-events: none;
white-space: pre-wrap;
color: ${({ theme }) => theme.textField.filled.active.placeholderColor};
${({ isLabelPresent, size }) => (isLabelPresent && size !== 'S' ? bottom : center)}
`;
3 changes: 2 additions & 1 deletion packages/core/src/components/TextField/TextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,9 @@ const Component: FC<TextFieldProps> = memo(
setCharacterCountValue(valueString.length);

if (mask) {
const maskedValue = getMaskedValue(e, mask);
const { maskedValue, selectionStart } = getMaskedValue(e, mask);
e.target.value = maskedValue;
e.target.setSelectionRange(selectionStart, selectionStart);
setMaskLabel(`${maskedValue}${mask.substr(maskedValue.length)}`);
}
props.onChange && props.onChange(e);
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/components/TextField/getMaskedValue.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ describe('getMaskedValue function', () => {
const maskedValue = (value: string, selectionStart?: number) => getMaskedValue({ target: { value, selectionStart } }, 'DD / MM / YYYY');

it('should return truncated value if selectionStart value is less then value length', () => {
expect(maskedValue('11 / 11 / 1111', 6)).toEqual('11 / 1');
expect(maskedValue('11 / 11 / 1111', 6)).toEqual({ maskedValue: '11 / 1 1 / 1111', selectionStart: 6 });
});

it('should not add extra char if value length is equal to mask length', () => {
expect(maskedValue('11 / 11 / 11111')).toEqual('11 / 11 / 1111');
expect(maskedValue('11 / 11 / 11111')).toEqual({ maskedValue: '11 / 11 / 1111', selectionStart: 14 });
});

it('should add special character in between', () => {
expect(maskedValue('11 / 111')).toEqual('11 / 11 / 1');
expect(maskedValue('11 / 111')).toEqual({ maskedValue: '11 / 11 / 1', selectionStart: 11 });
});
});
6 changes: 3 additions & 3 deletions packages/core/src/components/TextField/getMaskedValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ export const getMaskedValue = (event: React.ChangeEvent<HTMLInputElement>, mask:

//TODO: Need to remove this if, when we handle masking when user deletes from the middle of the text
if (selectionStart && selectionStart < value.length) {
maskedValue = value.slice(0, selectionStart);
maskedValue = `${value.slice(0, selectionStart)} ${value.slice(selectionStart)}`;
return { maskedValue, selectionStart };
} else {
maskedValue = value
.replace(specialCharsRegex, '')
.split('')
.reduce((acc: string, c: string) => applyMasking(acc + c, mask, selectionStart ?? 0), '');
return { maskedValue, selectionStart: maskedValue.length };
}

return maskedValue;
};

export default getMaskedValue;
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,7 @@ exports[`Form should render properly with initial state 1`] = `
-ms-user-select: none;
user-select: none;
pointer-events: none;
white-space: pre-wrap;
color: rgba(0,90,238,.2);
bottom: 0.7rem;
}
Expand Down Expand Up @@ -2960,6 +2961,7 @@ exports[`Form should render properly without initial state 1`] = `
-ms-user-select: none;
user-select: none;
pointer-events: none;
white-space: pre-wrap;
color: rgba(0,90,238,.2);
bottom: 0.7rem;
}
Expand Down

0 comments on commit 936577c

Please sign in to comment.