diff --git a/apps/react/src/app/features/online-board/components/flight-number-filter.scss b/apps/react/src/app/features/online-board/components/flight-number-filter.scss new file mode 100644 index 000000000..7b21b85f8 --- /dev/null +++ b/apps/react/src/app/features/online-board/components/flight-number-filter.scss @@ -0,0 +1,52 @@ +.flight-number-filter { + display: flex; + flex-direction: column; + gap: 16px; + padding: 16px 0; +} + +.flight-number-filter__group { + display: flex; + flex-direction: column; + gap: 8px; +} + +.flight-number-filter__label { + font-size: 12px; + font-weight: 500; + color: #666; + text-transform: uppercase; +} + +.flight-number-filter__input-group { + display: flex; + align-items: center; + gap: 8px; + border: 1px solid #e0e0e0; + border-radius: 4px; + padding: 4px; +} + +.flight-number-filter__prefix { + padding: 8px 12px; + font-weight: 600; + color: #1976d2; + background: #f5f5f5; + border-radius: 2px; +} + +.flight-number-filter__input { + flex: 1; + border: none; + padding: 8px; + font-size: 14px; + outline: none; + + &:focus { + background: #f9f9f9; + } +} + +.flight-number-filter__search-button { + margin-top: 8px; +} diff --git a/apps/react/src/app/features/online-board/components/flight-number-filter.tsx b/apps/react/src/app/features/online-board/components/flight-number-filter.tsx new file mode 100644 index 000000000..66e89aedb --- /dev/null +++ b/apps/react/src/app/features/online-board/components/flight-number-filter.tsx @@ -0,0 +1,70 @@ +import React, { useState } from 'react' +import { Button } from 'primereact/button' +import { useTranslation } from 'react-i18next' +import { CalendarInput } from '@app/components/calendar-input' +import './flight-number-filter.scss' + +export interface FlightNumberFilterProps { + onSearch: (flightNumber: string, date: Date) => void +} + +export const FlightNumberFilter: React.FC = ({ onSearch }) => { + const { t } = useTranslation() + const [flightNumber, setFlightNumber] = useState('') + const [date, setDate] = useState(new Date()) + + const handleSearch = () => { + if (flightNumber && date) { + onSearch(flightNumber, date) + } + } + + const handleClear = () => { + setFlightNumber('') + setDate(new Date()) + } + + return ( +
+
+ +
+ SU + setFlightNumber(e.target.value.toUpperCase())} + data-testid="flight-number-input" + maxLength={4} + /> +
+
+ +
+ + +
+ +
+ ) +} diff --git a/apps/react/src/app/features/online-board/components/index.ts b/apps/react/src/app/features/online-board/components/index.ts index 3dd50bb84..419c42985 100644 --- a/apps/react/src/app/features/online-board/components/index.ts +++ b/apps/react/src/app/features/online-board/components/index.ts @@ -1 +1,3 @@ export { OnlineBoardFilter } from './online-board-filter' +export { FlightNumberFilter } from './flight-number-filter' +export { RouteFilter } from './route-filter' diff --git a/apps/react/src/app/features/online-board/components/online-board-filter.scss b/apps/react/src/app/features/online-board/components/online-board-filter.scss index 618a78066..06de4f43c 100644 --- a/apps/react/src/app/features/online-board/components/online-board-filter.scss +++ b/apps/react/src/app/features/online-board/components/online-board-filter.scss @@ -1,4 +1,23 @@ .online-board-filter { width: 100%; - min-height: 200px; + + :global { + .p-accordion { + border: 1px solid #e0e0e0; + border-radius: 4px; + + .p-accordion-header { + padding: 0; + + a { + padding: 12px 16px; + font-weight: 500; + } + } + + .p-accordion-content { + padding: 0 16px; + } + } + } } diff --git a/apps/react/src/app/features/online-board/components/online-board-filter.tsx b/apps/react/src/app/features/online-board/components/online-board-filter.tsx index c8e6af38b..37fb76de9 100644 --- a/apps/react/src/app/features/online-board/components/online-board-filter.tsx +++ b/apps/react/src/app/features/online-board/components/online-board-filter.tsx @@ -1,14 +1,47 @@ -import React from 'react' +import React, { useState } from 'react' +import { Accordion, AccordionTab } from 'primereact/accordion' +import { useNavigate } from 'react-router-dom' +import { useTranslation } from 'react-i18next' +import { FlightNumberFilter } from './flight-number-filter' +import { RouteFilter } from './route-filter' import './online-board-filter.scss' -export interface OnlineBoardFilterProps { - 'data-testid'?: string -} +export const OnlineBoardFilter: React.FC = () => { + const { t } = useTranslation() + const navigate = useNavigate() + const [activeTab, setActiveTab] = useState(0) + + const handleFlightNumberSearch = (flightNumber: string, date: Date) => { + // Navigate to flight number search results + const params = btoa(JSON.stringify({ flightNumber, date: date.toISOString() })) + navigate(`/onlineboard/flight/${params}`) + } + + const handleRouteSearch = (departure: string, arrival: string, date: Date) => { + // Navigate to route search results + const params = btoa(JSON.stringify({ departure, arrival, date: date.toISOString() })) + navigate(`/onlineboard/route/${params}`) + } -export const OnlineBoardFilter: React.FC = ({ 'data-testid': dataTestId }) => { return ( -
- {/* Filter component will be implemented in the next task */} +
+ { + const index = typeof e.index === 'number' ? e.index : (Array.isArray(e.index) ? e.index[0] : 0) + setActiveTab(index) + }}> + + + + + + +
) } diff --git a/apps/react/src/app/features/online-board/components/route-filter.scss b/apps/react/src/app/features/online-board/components/route-filter.scss new file mode 100644 index 000000000..d289bfb8a --- /dev/null +++ b/apps/react/src/app/features/online-board/components/route-filter.scss @@ -0,0 +1,28 @@ +.route-filter { + display: flex; + flex-direction: column; + gap: 16px; + padding: 16px 0; +} + +.route-filter__group { + display: flex; + flex-direction: column; + gap: 8px; +} + +.route-filter__label { + font-size: 12px; + font-weight: 500; + color: #666; + text-transform: uppercase; +} + +.route-filter__swap { + align-self: center; + margin: 8px 0; +} + +.route-filter__search-button { + margin-top: 8px; +} diff --git a/apps/react/src/app/features/online-board/components/route-filter.tsx b/apps/react/src/app/features/online-board/components/route-filter.tsx new file mode 100644 index 000000000..fb202fdc9 --- /dev/null +++ b/apps/react/src/app/features/online-board/components/route-filter.tsx @@ -0,0 +1,89 @@ +import React, { useState } from 'react' +import { Button } from 'primereact/button' +import { useTranslation } from 'react-i18next' +import { CityAutocomplete, City } from '@app/components/city-autocomplete' +import { CalendarInput } from '@app/components/calendar-input' +import { TimeSelector } from '@app/components/time-selector' +import './route-filter.scss' + +export interface RouteFilterProps { + onSearch: (departure: string, arrival: string, date: Date) => void +} + +export const RouteFilter: React.FC = ({ onSearch }) => { + const { t } = useTranslation() + const [departure, setDeparture] = useState(null) + const [arrival, setArrival] = useState(null) + const [date, setDate] = useState(new Date()) + const [startTime, setStartTime] = useState('00:00') + const [endTime, setEndTime] = useState('23:59') + + const handleSearch = () => { + if (departure && arrival && date) { + onSearch(departure.code, arrival.code, date) + } + } + + const handleSwap = () => { + const temp = departure + setDeparture(arrival) + setArrival(temp) + } + + return ( +
+
+ + +
+ +
+ ) +}