diff --git a/packages/app/app/page.tsx b/packages/app/app/page.tsx index 0b850601..452ad54f 100644 --- a/packages/app/app/page.tsx +++ b/packages/app/app/page.tsx @@ -1,17 +1,25 @@ -import GeneralLayout from '../src/layouts/GeneralLayout'; -import Lead from '../src/components/Lead'; -import SearchFlightsForm from '../src/components/SearchFlightsForm'; -import { fetchCompanies } from '../src/services/fetch-companies'; -import { fetchAirports } from '../src/services/fetch-airports'; +import GeneralLayout from "../src/layouts/GeneralLayout"; +import Lead from "../src/components/Lead"; +import SearchFlightsForm from "../src/components/SearchFlightsForm"; +import { fetchCompanies } from "../src/services/fetch-companies"; +import { fetchAircraftIcaoCodes } from "../src/services/fetch-aircraft-icao-codes"; +import { fetchAirports } from "../src/services/fetch-airports"; export const revalidate = 3600; export default async function Page() { - const companies = await fetchCompanies() - const airports = await fetchAirports(); + const companies = await fetchCompanies(); + const airports = await fetchAirports(); + const aircraftIcaoCodes = await fetchAircraftIcaoCodes(); - return - To begin, fill at least one of the following fields. - + return ( + + To begin, fill at least one of the following fields. + + ); } diff --git a/packages/app/src/components/SearchFlightsForm/index.tsx b/packages/app/src/components/SearchFlightsForm/index.tsx index 3cc3179a..6386100c 100644 --- a/packages/app/src/components/SearchFlightsForm/index.tsx +++ b/packages/app/src/components/SearchFlightsForm/index.tsx @@ -1,38 +1,55 @@ -"use client" +"use client"; -import { ChangeEventHandler, FC, useState } from 'react' -import { Airport } from '../../services/fetch-airports' -import { formatAirport } from '../../utils/format-airport' -import Button from '../Button' -import { SelectInput } from '../SelectInput' -import styles from './index.module.css' +import { ChangeEventHandler, FC, useState } from "react"; +import { Airport } from "../../services/fetch-airports"; +import { formatAirport } from "../../utils/format-airport"; +import Button from "../Button"; +import { SelectInput } from "../SelectInput"; +import styles from "./index.module.css"; -export type SearchFlightsFormFields = { departureIcao: string; arrivalIcao: string, company: string } +export type SearchFlightsFormFields = { + departureIcao: string; + arrivalIcao: string; + company: string; + aircraftIcaoCode: string; +}; type Props = { - companies: string[] - airports: Airport[] -} + companies: string[]; + aircraftIcaoCodes: string[]; + airports: Airport[]; +}; -const SearchFlightsForm: FC = ({ companies, airports }) => { +const SearchFlightsForm: FC = ({ + companies, + aircraftIcaoCodes, + airports, +}) => { const [form, setForm] = useState({ - arrivalIcao: '', - departureIcao: '', - company: '' - }) + arrivalIcao: "", + departureIcao: "", + company: "", + aircraftIcaoCode: "", + }); - const isSubmitDisabled = form.arrivalIcao.trim().length === 0 && form.departureIcao.trim().length === 0 && form.company.length === 0 + const isSubmitDisabled = + form.arrivalIcao.trim().length === 0 && + form.departureIcao.trim().length === 0 && + form.company.length === 0 && + form.aircraftIcaoCode.length === 0; - const onChange: ChangeEventHandler = evt => { - setForm(form => ({ + const onChange: ChangeEventHandler = ( + evt + ) => { + setForm((form) => ({ ...form, - [evt.target.name]: evt.target.value.toUpperCase() - })) - } + [evt.target.name]: evt.target.value.toUpperCase(), + })); + }; - const airportsOptions = airports.map(airport => { - return { value: airport.AeroCode, label: formatAirport(airport) } - }) + const airportsOptions = airports.map((airport) => { + return { value: airport.AeroCode, label: formatAirport(airport) }; + }); return (
@@ -41,7 +58,9 @@ const SearchFlightsForm: FC = ({ companies, airports }) => { setForm(form => ({ ...form, departureIcao }))} + onChange={(departureIcao) => + setForm((form) => ({ ...form, departureIcao })) + } /> @@ -50,28 +69,64 @@ const SearchFlightsForm: FC = ({ companies, airports }) => { setForm(form => ({ ...form, arrivalIcao }))} + onChange={(arrivalIcao) => + setForm((form) => ({ ...form, arrivalIcao })) + } />
- + {companies.map((company) => { - return + return ( + + ); })}
-
+
+ + +
+ +
- + - ) -} + ); +}; -export default SearchFlightsForm +export default SearchFlightsForm; diff --git a/packages/app/src/services/fetch-aircraft-icao-codes.ts b/packages/app/src/services/fetch-aircraft-icao-codes.ts new file mode 100644 index 00000000..885bbae3 --- /dev/null +++ b/packages/app/src/services/fetch-aircraft-icao-codes.ts @@ -0,0 +1,11 @@ +import { FlightModel } from "@mach/database"; +import { QueryTypes } from "sequelize"; + +export async function fetchAircraftIcaoCodes() { + const companies = await FlightModel.sequelize?.query( + `SELECT DISTINCT(aircraft#>>'{icaoCode}') AS "aircraftIcaoCode" FROM "flights" AS "flight";`, + { type: QueryTypes.SELECT } + ); + + return companies?.map((v: any) => v.aircraftIcaoCode) ?? []; +} diff --git a/packages/app/src/services/fetch-flights.ts b/packages/app/src/services/fetch-flights.ts index 42a86d87..098df307 100644 --- a/packages/app/src/services/fetch-flights.ts +++ b/packages/app/src/services/fetch-flights.ts @@ -16,6 +16,10 @@ const schema = z.object({ .string() .transform((v) => v.toUpperCase()) .optional(), + aircraftIcaoCode: z + .string() + .transform((v) => v.toUpperCase()) + .optional(), onlyCurrent: z .string() .transform((v) => Boolean(v)) @@ -31,6 +35,9 @@ export async function fetchFlights(searchParams: Record) { ...(where.departureIcao && { departureIcao: where.departureIcao }), ...(where.arrivalIcao && { arrivalIcao: where.arrivalIcao }), ...(where.company && { company: where.company }), + ...(where.aircraftIcaoCode && { + aircraft: { icaoCode: where.aircraftIcaoCode }, + }), ...(where.onlyCurrent && { beginDate: { [Op.lte]: today,