Add cabin class dropdown to RouteFilter component

- Add cabinClass state with type 'economy' | 'business' | 'first' (default: economy)
- Add showCabinDropdown state to control visibility
- Add cabin-class-dropdown button to toggle visibility
- Add cabin-economy, cabin-business, cabin-first selection buttons
- Add cabin-class-display div showing selected cabin class
- Pass cabinClass in handleSearch callback
- Update RouteFilterProps with initialCabinClass prop
- Add SCSS styling for cabin class dropdown and options
- Integrate into OnlineBoardFilter to pass initialCabinClass
- Integrate into OnlineBoardSearchPage to decode cabinClass from URL params
This commit is contained in:
gnezim
2026-04-06 08:33:56 +03:00
parent ec0c67db91
commit e426317eef
6 changed files with 123 additions and 6 deletions
@@ -15,6 +15,7 @@ interface OnlineBoardFilterProps {
flightNumber?: string
tripType?: string
passengers?: { adults: number, children: number, infants: number }
cabinClass?: 'economy' | 'business' | 'first'
}
}
@@ -29,7 +30,7 @@ export const OnlineBoardFilter: React.FC<OnlineBoardFilterProps> = ({ initialSea
navigate(`/onlineboard/flight/${params}`)
}
const handleRouteSearch = (departure: string, arrival: string, date: Date, returnDate?: Date | null, tripType?: string, passengers?: { adults: number, children: number, infants: number }) => {
const handleRouteSearch = (departure: string, arrival: string, date: Date, returnDate?: Date | null, tripType?: string, passengers?: { adults: number, children: number, infants: number }, cabinClass?: 'economy' | 'business' | 'first') => {
// Navigate to route search results
const params = btoa(JSON.stringify({
departure,
@@ -38,6 +39,7 @@ export const OnlineBoardFilter: React.FC<OnlineBoardFilterProps> = ({ initialSea
...(returnDate && { returnDate: returnDate.toISOString() }),
...(tripType && { tripType }),
...(passengers && { passengers }),
...(cabinClass && { cabinClass }),
}))
navigate(`/onlineboard/route/${params}`)
}
@@ -66,6 +68,7 @@ export const OnlineBoardFilter: React.FC<OnlineBoardFilterProps> = ({ initialSea
initialReturnDate={initialSearchParams?.returnDate}
initialTripType={initialSearchParams?.tripType}
initialPassengers={initialSearchParams?.passengers}
initialCabinClass={initialSearchParams?.cabinClass}
/>
</AccordionTab>
</Accordion>
@@ -125,6 +125,69 @@
}
}
.route-filter__cabin-class-group {
position: relative;
}
.route-filter__cabin-class-dropdown {
width: 100%;
justify-content: space-between;
padding: 8px 12px;
background-color: #f5f5f5;
border-radius: 4px;
font-size: 14px;
text-align: left;
&:hover {
background-color: #ececec;
}
}
.route-filter__cabin-class-options {
display: flex;
flex-direction: column;
gap: 0;
padding: 0;
background-color: #fafafa;
border: 1px solid #e0e0e0;
border-top: none;
border-radius: 0 0 4px 4px;
margin-top: -4px;
}
.route-filter__cabin-option {
width: 100%;
justify-content: flex-start;
padding: 8px 12px;
border-radius: 0;
font-size: 14px;
border-bottom: 1px solid #e0e0e0;
background-color: transparent;
&:last-child {
border-bottom: none;
}
&:hover {
background-color: #f0f0f0;
}
&.active {
background-color: #e3f2fd;
font-weight: 600;
color: #0066cc;
}
}
.route-filter__cabin-class-display {
margin-top: 4px;
padding: 4px 8px;
background-color: #f5f5f5;
border-radius: 4px;
font-size: 12px;
color: #666;
}
.route-filter__actions {
display: flex;
gap: 8px;
@@ -13,13 +13,14 @@ export interface PassengerCounts {
}
export interface RouteFilterProps {
onSearch?: (departure: string, arrival: string, date: Date, returnDate?: Date | null, tripType?: string, passengers?: PassengerCounts) => void
onSearch?: (departure: string, arrival: string, date: Date, returnDate?: Date | null, tripType?: string, passengers?: PassengerCounts, cabinClass?: 'economy' | 'business' | 'first') => void
initialDeparture?: string
initialArrival?: string
initialDate?: Date | string
initialReturnDate?: Date | string
initialTripType?: string
initialPassengers?: PassengerCounts
initialCabinClass?: 'economy' | 'business' | 'first'
}
// Validation service
@@ -77,7 +78,8 @@ export const RouteFilter: React.FC<RouteFilterProps> = ({
initialDate,
initialReturnDate,
initialTripType,
initialPassengers
initialPassengers,
initialCabinClass
}) => {
const { t } = useTranslation()
const validated = validatePassengerCounts(initialPassengers)
@@ -102,6 +104,8 @@ export const RouteFilter: React.FC<RouteFilterProps> = ({
const [children, setChildren] = useState(validated.children)
const [infants, setInfants] = useState(validated.infants)
const [showPassengerDropdown, setShowPassengerDropdown] = useState(false)
const [cabinClass, setCabinClass] = useState<'economy' | 'business' | 'first'>(initialCabinClass || 'economy')
const [showCabinDropdown, setShowCabinDropdown] = useState(false)
const totalPassengers = adults + children + infants
const maxPassengers = 9
@@ -119,10 +123,10 @@ export const RouteFilter: React.FC<RouteFilterProps> = ({
const handleSearch = useCallback(() => {
if (validateRouteParams(departure, arrival, date) && onSearch) {
// Pass all search parameters including return date for round trips and passenger counts
onSearch(departure!.code, arrival!.code, date!, returnDate, tripType, { adults, children, infants })
// 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)
}
}, [departure, arrival, date, returnDate, tripType, adults, children, infants, onSearch])
}, [departure, arrival, date, returnDate, tripType, adults, children, infants, cabinClass, onSearch])
const handleSwap = () => {
const temp = departure
@@ -238,6 +242,52 @@ export const RouteFilter: React.FC<RouteFilterProps> = ({
</div>
</div>
<div className="route-filter__group route-filter__cabin-class-group">
<Button
label={t('SHARED.CABIN_CLASS')}
icon={showCabinDropdown ? 'pi pi-chevron-up' : 'pi pi-chevron-down'}
onClick={() => setShowCabinDropdown(!showCabinDropdown)}
className="p-button-text route-filter__cabin-class-dropdown"
data-testid="cabin-class-dropdown"
/>
{showCabinDropdown && (
<div className="route-filter__cabin-class-options">
<Button
label={t('SHARED.ECONOMY')}
onClick={() => {
setCabinClass('economy')
setShowCabinDropdown(false)
}}
className={`p-button-text route-filter__cabin-option ${cabinClass === 'economy' ? 'active' : ''}`}
data-testid="cabin-economy"
/>
<Button
label={t('SHARED.BUSINESS')}
onClick={() => {
setCabinClass('business')
setShowCabinDropdown(false)
}}
className={`p-button-text route-filter__cabin-option ${cabinClass === 'business' ? 'active' : ''}`}
data-testid="cabin-business"
/>
<Button
label={t('SHARED.FIRST')}
onClick={() => {
setCabinClass('first')
setShowCabinDropdown(false)
}}
className={`p-button-text route-filter__cabin-option ${cabinClass === 'first' ? 'active' : ''}`}
data-testid="cabin-first"
/>
</div>
)}
<div className="route-filter__cabin-class-display" data-testid="cabin-class-display">
{t(`SHARED.${cabinClass.toUpperCase()}`)}
</div>
</div>
<div className="route-filter__group">
<label className="route-filter__label">{t('SHARED.DATE')}</label>
<CalendarInput
@@ -121,6 +121,7 @@ export const OnlineBoardSearchPage: React.FC = () => {
flightNumber: searchParams.flightNumber,
returnDate: searchParams.returnDate,
tripType: searchParams.tripType,
cabinClass: searchParams.cabinClass,
}
: undefined
}