mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 21:46:49 +00:00
fix(trips): the trip form drops its complaint once you edit, and the typed date hint follows your language
"Title is required" stayed on screen after the title was typed, until the next save. Any edit in the trip form, desktop and phone, now clears the last save's complaint; the next save checks again. The keyboard date field always hinted DD.MM.YYYY, while it was filled and read back in the user's own order: a Korean user saw "2026. 12. 10." under a German hint. The hint is now the locale's own pattern (YYYY. MM. DD. in Korean, MM/DD/YYYY in US English), and the field's name is translated. Refs #2604
This commit is contained in:
@@ -104,14 +104,14 @@ describe('CustomDatePicker', () => {
|
||||
const user = userEvent.setup();
|
||||
render(<CustomDatePicker value="" onChange={onChange} />);
|
||||
await user.click(screen.getByRole('button', { name: /enter date manually/i }));
|
||||
expect(screen.getByPlaceholderText('DD.MM.YYYY')).toBeTruthy();
|
||||
expect(screen.getByRole('textbox', { name: 'Enter date manually' })).toBeTruthy();
|
||||
});
|
||||
|
||||
it('FE-COMP-DATEPICKER-012: text input accepts ISO format YYYY-MM-DD', async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<CustomDatePicker value="" onChange={onChange} />);
|
||||
await user.click(screen.getByRole('button', { name: /enter date manually/i }));
|
||||
const input = screen.getByPlaceholderText('DD.MM.YYYY');
|
||||
const input = screen.getByRole('textbox', { name: 'Enter date manually' });
|
||||
fireEvent.change(input, { target: { value: '2026-07-04' } });
|
||||
fireEvent.keyDown(input, { key: 'Enter' });
|
||||
expect(onChange).toHaveBeenCalledWith('2026-07-04');
|
||||
@@ -121,7 +121,7 @@ describe('CustomDatePicker', () => {
|
||||
const user = userEvent.setup();
|
||||
render(<CustomDatePicker value="" onChange={onChange} />);
|
||||
await user.click(screen.getByRole('button', { name: /enter date manually/i }));
|
||||
const input = screen.getByPlaceholderText('DD.MM.YYYY');
|
||||
const input = screen.getByRole('textbox', { name: 'Enter date manually' });
|
||||
fireEvent.change(input, { target: { value: '17.07.2026' } });
|
||||
fireEvent.keyDown(input, { key: 'Enter' });
|
||||
expect(onChange).toHaveBeenCalledWith('2026-07-17');
|
||||
@@ -131,7 +131,7 @@ describe('CustomDatePicker', () => {
|
||||
const user = userEvent.setup();
|
||||
render(<CustomDatePicker value="" onChange={onChange} />);
|
||||
await user.click(screen.getByRole('button', { name: /enter date manually/i }));
|
||||
const input = screen.getByPlaceholderText('DD.MM.YYYY');
|
||||
const input = screen.getByRole('textbox', { name: 'Enter date manually' });
|
||||
fireEvent.change(input, { target: { value: '31.02.2026' } });
|
||||
fireEvent.keyDown(input, { key: 'Enter' });
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
@@ -141,7 +141,7 @@ describe('CustomDatePicker', () => {
|
||||
const user = userEvent.setup();
|
||||
render(<CustomDatePicker value="" onChange={onChange} />);
|
||||
await user.click(screen.getByRole('button', { name: /enter date manually/i }));
|
||||
const input = screen.getByPlaceholderText('DD.MM.YYYY');
|
||||
const input = screen.getByRole('textbox', { name: 'Enter date manually' });
|
||||
fireEvent.change(input, { target: { value: '29.02.2024' } });
|
||||
fireEvent.keyDown(input, { key: 'Enter' });
|
||||
expect(onChange).toHaveBeenCalledWith('2024-02-29');
|
||||
@@ -151,9 +151,9 @@ describe('CustomDatePicker', () => {
|
||||
const user = userEvent.setup();
|
||||
render(<CustomDatePicker value="" onChange={onChange} />);
|
||||
await user.click(screen.getByRole('button', { name: /enter date manually/i }));
|
||||
const input = screen.getByPlaceholderText('DD.MM.YYYY');
|
||||
const input = screen.getByRole('textbox', { name: 'Enter date manually' });
|
||||
fireEvent.keyDown(input, { key: 'Escape' });
|
||||
expect(screen.queryByPlaceholderText('DD.MM.YYYY')).toBeNull();
|
||||
expect(screen.queryByRole('textbox', { name: 'Enter date manually' })).toBeNull();
|
||||
expect(screen.getAllByRole('button').length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
@@ -183,7 +183,7 @@ describe('CustomDatePicker', () => {
|
||||
const user = userEvent.setup();
|
||||
render(<CustomDatePicker value="" onChange={onChange} min="2026-03-10" max="2026-03-20" />);
|
||||
await user.click(screen.getByRole('button', { name: /enter date manually/i }));
|
||||
const input = screen.getByPlaceholderText('DD.MM.YYYY');
|
||||
const input = screen.getByRole('textbox', { name: 'Enter date manually' });
|
||||
fireEvent.change(input, { target: { value: '2026-03-25' } });
|
||||
fireEvent.keyDown(input, { key: 'Enter' });
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
@@ -503,22 +503,22 @@ describe('CustomDatePicker branches', () => {
|
||||
openCalendar();
|
||||
fireEvent.click(screen.getByRole('button', { name: /enter date manually/i }));
|
||||
|
||||
expect(screen.getByPlaceholderText('DD.MM.YYYY')).toHaveProperty('value', '');
|
||||
expect(screen.getByRole('textbox', { name: 'Enter date manually' })).toHaveProperty('value', '');
|
||||
});
|
||||
|
||||
it('FE-W5DP-010: submitting an empty manual entry does nothing', () => {
|
||||
render(<CustomDatePicker value="" onChange={onChange} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /enter date manually/i }));
|
||||
fireEvent.blur(screen.getByPlaceholderText('DD.MM.YYYY'));
|
||||
fireEvent.blur(screen.getByRole('textbox', { name: 'Enter date manually' }));
|
||||
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
expect(screen.queryByPlaceholderText('DD.MM.YYYY')).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('textbox', { name: 'Enter date manually' })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('FE-W5DP-011: a manual entry without three number groups is ignored', () => {
|
||||
render(<CustomDatePicker value="" onChange={onChange} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /enter date manually/i }));
|
||||
const input = screen.getByPlaceholderText('DD.MM.YYYY');
|
||||
const input = screen.getByRole('textbox', { name: 'Enter date manually' });
|
||||
fireEvent.change(input, { target: { value: '17.07' } });
|
||||
fireEvent.keyDown(input, { key: 'Enter' });
|
||||
|
||||
@@ -528,7 +528,7 @@ describe('CustomDatePicker branches', () => {
|
||||
it('FE-W5DP-012: a manual entry already in locale order is taken as typed', () => {
|
||||
render(<CustomDatePicker value="" onChange={onChange} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /enter date manually/i }));
|
||||
const input = screen.getByPlaceholderText('DD.MM.YYYY');
|
||||
const input = screen.getByRole('textbox', { name: 'Enter date manually' });
|
||||
fireEvent.change(input, { target: { value: '07/17/2026' } });
|
||||
fireEvent.keyDown(input, { key: 'Enter' });
|
||||
|
||||
@@ -538,7 +538,7 @@ describe('CustomDatePicker branches', () => {
|
||||
it('FE-W5DP-013: a two-digit year is expanded into the 2000s', () => {
|
||||
render(<CustomDatePicker value="" onChange={onChange} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /enter date manually/i }));
|
||||
const input = screen.getByPlaceholderText('DD.MM.YYYY');
|
||||
const input = screen.getByRole('textbox', { name: 'Enter date manually' });
|
||||
fireEvent.change(input, { target: { value: '07/17/26' } });
|
||||
fireEvent.keyDown(input, { key: 'Enter' });
|
||||
|
||||
@@ -548,7 +548,7 @@ describe('CustomDatePicker branches', () => {
|
||||
it('FE-W5DP-014: an impossible day/month combination is rejected', () => {
|
||||
render(<CustomDatePicker value="" onChange={onChange} />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /enter date manually/i }));
|
||||
const input = screen.getByPlaceholderText('DD.MM.YYYY');
|
||||
const input = screen.getByRole('textbox', { name: 'Enter date manually' });
|
||||
fireEvent.change(input, { target: { value: '13/45/2026' } });
|
||||
fireEvent.keyDown(input, { key: 'Enter' });
|
||||
|
||||
@@ -558,7 +558,7 @@ describe('CustomDatePicker branches', () => {
|
||||
it('FE-W5DP-015: a localised manual entry outside [min,max] is rejected', () => {
|
||||
render(<CustomDatePicker value="" onChange={onChange} min="2026-03-10" max="2026-03-20" />);
|
||||
fireEvent.click(screen.getByRole('button', { name: /enter date manually/i }));
|
||||
const input = screen.getByPlaceholderText('DD.MM.YYYY');
|
||||
const input = screen.getByRole('textbox', { name: 'Enter date manually' });
|
||||
fireEvent.change(input, { target: { value: '03/25/2026' } });
|
||||
fireEvent.keyDown(input, { key: 'Enter' });
|
||||
|
||||
@@ -743,7 +743,7 @@ describe('CustomDatePicker branches', () => {
|
||||
|
||||
fireEvent.click(keyboard);
|
||||
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
||||
expect(screen.getByPlaceholderText('DD.MM.YYYY')).toHaveProperty('value', '03/15/2026');
|
||||
expect(screen.getByRole('textbox', { name: 'Enter date manually' })).toHaveProperty('value', '03/15/2026');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { localIsoDate } from '../../utils/localDate';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { useTranslation } from '../../i18n';
|
||||
import { dateInputPattern } from '../../utils/dateInputPattern';
|
||||
import { useRemeasureSignal } from '../../hooks/useAnchoredPosition';
|
||||
import { useWeekStartDay } from '../../hooks/useWeekStartDay';
|
||||
import { leadingBlanks, weekdayLabels } from '../../utils/calendarWeek';
|
||||
@@ -276,8 +277,8 @@ export function CustomDatePicker({
|
||||
if (e.key === 'Escape') setIsTyping(false);
|
||||
}}
|
||||
onBlur={handleTextSubmit}
|
||||
placeholder="DD.MM.YYYY"
|
||||
aria-label="Enter date manually"
|
||||
placeholder={dateInputPattern(locale)}
|
||||
aria-label={t('common.datepicker.enterManually')}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '8px 14px',
|
||||
|
||||
Reference in New Issue
Block a user