Add validation error displays to RouteFilter component

- Add three error display elements with test IDs: departure-error, same-city-error, validation-error
- Add validation state management: departureError, arrivalError, sameAirportError, searchValidationError
- Add validateDepartureInput() function for input validation (reuses validateCityCode)
- Implement same-city validation in useEffect to detect duplicate departure/arrival
- Update handleSearch() to check all required fields and show validation-error when missing
- Add error styling: .route-filter__error with red text (#d32f2f), light red background (#ffebee), and left border
- Same-city error shows inline below arrival input
- Search validation error displays below action buttons
- Errors automatically clear when conditions are fixed
This commit is contained in:
gnezim
2026-04-06 08:38:56 +03:00
parent afc81cab3b
commit a3e5ee9bdd
2 changed files with 75 additions and 0 deletions
@@ -243,3 +243,22 @@
flex: 1;
}
}
.route-filter__error {
margin-top: 4px;
padding: 6px 8px;
background-color: #ffebee;
border-left: 3px solid #d32f2f;
border-radius: 2px;
font-size: 12px;
color: #d32f2f;
font-weight: 500;
}
.route-filter__error-message {
display: flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: #d32f2f;
}
@@ -46,6 +46,13 @@ const validateCityCode = (code: string | undefined): boolean => {
return /^[A-Z]{3}$/.test(code.toUpperCase())
}
// Validate departure input for invalid characters
const validateDepartureInput = (code: string | undefined): boolean => {
if (!code) return true // Empty is not invalid, just incomplete
// Only allow 3-letter airport codes (A-Z)
return validateCityCode(code)
}
const validateRouteParams = (departure: City | null, arrival: City | null, date: Date | null): boolean => {
if (!departure || !arrival || !date) return false
if (!validateCityCode(departure.code) || !validateCityCode(arrival.code)) return false
@@ -106,6 +113,10 @@ export const RouteFilter: React.FC<RouteFilterProps> = ({
const [showPassengerDropdown, setShowPassengerDropdown] = useState(false)
const [cabinClass, setCabinClass] = useState<'economy' | 'business' | 'first'>(initialCabinClass || 'economy')
const [showCabinDropdown, setShowCabinDropdown] = useState(false)
const [departureError, setDepartureError] = useState<string>('')
const [arrivalError, setArrivalError] = useState<string>('')
const [sameAirportError, setSameAirportError] = useState(false)
const [searchValidationError, setSearchValidationError] = useState<string>('')
const totalPassengers = adults + children + infants
const maxPassengers = 9
@@ -113,6 +124,16 @@ export const RouteFilter: React.FC<RouteFilterProps> = ({
const isSearchDisabled = !validateRouteParams(departure, arrival, date)
// Validate departure and arrival on change
useEffect(() => {
// Check for same city error
if (departure && arrival && departure.code === arrival.code) {
setSameAirportError(true)
} else {
setSameAirportError(false)
}
}, [departure, arrival])
// Auto-search when departure or arrival city is selected
useEffect(() => {
if ((validateMinimalRouteParams(departure) || validateMinimalRouteParams(arrival)) && onSearch) {
@@ -122,6 +143,21 @@ export const RouteFilter: React.FC<RouteFilterProps> = ({
}, [departure, arrival])
const handleSearch = useCallback(() => {
// Clear previous search validation error
setSearchValidationError('')
// Check for all required fields
if (!departure || !arrival || !date) {
setSearchValidationError('Please fill in all required fields')
return
}
// Check for same city error
if (departure.code === arrival.code) {
setSameAirportError(true)
return
}
if (validateRouteParams(departure, arrival, date) && onSearch) {
// Pass all search parameters including return date for round trips, passenger counts, and cabin class
onSearch(departure!.code, arrival!.code, date!, returnDate, tripType, { adults, children, infants }, cabinClass)
@@ -192,6 +228,11 @@ export const RouteFilter: React.FC<RouteFilterProps> = ({
{departure.code}
</div>
)}
{departureError && (
<div data-testid="departure-error" className="route-filter__error">
{departureError}
</div>
)}
</div>
<Button
@@ -214,6 +255,16 @@ export const RouteFilter: React.FC<RouteFilterProps> = ({
{arrival.code}
</div>
)}
{sameAirportError && (
<div data-testid="same-city-error" className="route-filter__error">
Departure and arrival cities must be different
</div>
)}
{arrivalError && (
<div data-testid="arrival-error" className="route-filter__error">
{arrivalError}
</div>
)}
</div>
<div className="route-filter__trip-type">
@@ -458,6 +509,11 @@ export const RouteFilter: React.FC<RouteFilterProps> = ({
data-testid="clear-filters-button"
/>
</div>
{searchValidationError && (
<div data-testid="validation-error" className="route-filter__error">
{searchValidationError}
</div>
)}
</div>
)
}