diff --git a/web/app/routes/logbook.aircraft/route.tsx b/web/app/routes/logbook.aircraft/route.tsx index 1aa57b2..d205761 100644 --- a/web/app/routes/logbook.aircraft/route.tsx +++ b/web/app/routes/logbook.aircraft/route.tsx @@ -1,4 +1,5 @@ import ErrorDisplay from "@/ui/error-display"; +import AircraftForm from "@/ui/form/aircraft-form"; import { useApi } from "@/util/api"; import { AircraftFormSchema, AircraftSchema } from "@/util/types"; import { @@ -125,54 +126,9 @@ function NewAircraftModal({ opened: boolean; close: () => void; }) { - const newForm = useForm({ - initialValues: { - tail_no: "", - make: "", - model: "", - aircraft_category: "", - aircraft_class: "", - hobbs: 0.0, - }, - validate: { - tail_no: (value) => - value === null || value.trim() === "" - ? "Please enter a tail number" - : null, - make: (value) => - value === null || value.trim() === "" ? "Please enter a make" : null, - model: (value) => - value === null || value.trim() === "" ? "Please enter a model" : null, - aircraft_category: (value) => - value === null || value.trim() === "" - ? "Please select a category" - : null, - aircraft_class: (value) => - value === null || value.trim() === "" ? "Please select a class" : null, - }, - }); - const client = useApi(); const queryClient = useQueryClient(); - const categories = useQuery({ - queryKey: ["categories"], - queryFn: async () => - await client.get(`/aircraft/categories`).then((res) => res.data), - }); - - const [category, setCategory] = useState(""); - const [classSelection, setClassSelection] = useState(""); - - const classes = useQuery({ - queryKey: ["classes", category], - queryFn: async () => - await client - .get(`/aircraft/class?category=${category}`) - .then((res) => res.data), - enabled: !!category, - }); - const addAircraft = useMutation({ mutationFn: async (values: AircraftFormSchema) => { const newAircraft = values; @@ -190,84 +146,13 @@ function NewAircraftModal({ return ( -
addAircraft.mutate(values))}> - - - - - - - - - {addAircraft.isError ? ( - - {(addAircraft.error as AxiosError)?.response?.data?.detail ?? - "Error adding aircraft"} - - ) : addAircraft.isPending ? ( - Adding aircraft... - ) : null} - - - - -
+
); } diff --git a/web/app/ui/form/aircraft-form.tsx b/web/app/ui/form/aircraft-form.tsx new file mode 100644 index 0000000..253cd17 --- /dev/null +++ b/web/app/ui/form/aircraft-form.tsx @@ -0,0 +1,173 @@ +import { useApi } from "@/util/api"; +import { AircraftFormSchema } from "@/util/types"; +import { + Button, + Container, + Group, + NumberInput, + Select, + Stack, + Text, + TextInput, +} from "@mantine/core"; +import { useForm } from "@mantine/form"; +import { IconPencil, IconX } from "@tabler/icons-react"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { AxiosError } from "axios"; +import { useState } from "react"; + +export default function AircraftForm({ + onSubmit, + isError, + error, + isPending, + initialValues, + submitButtonLabel, + withCancelButton, + cancelFunc, +}: { + onSubmit: (values: AircraftFormSchema) => void; + isError: boolean; + error: Error | null; + isPending: boolean; + initialValues?: AircraftFormSchema | null; + mah?: string; + submitButtonLabel?: string; + withCancelButton?: boolean; + cancelFunc?: () => void; +}) { + const newForm = useForm({ + initialValues: initialValues ?? { + tail_no: "", + make: "", + model: "", + aircraft_category: "", + aircraft_class: "", + hobbs: 0.0, + }, + validate: { + tail_no: (value) => + value === null || value.trim() === "" + ? "Please enter a tail number" + : null, + make: (value) => + value === null || value.trim() === "" ? "Please enter a make" : null, + model: (value) => + value === null || value.trim() === "" ? "Please enter a model" : null, + aircraft_category: (value) => + value === null || value.trim() === "" + ? "Please select a category" + : null, + aircraft_class: (value) => + value === null || value.trim() === "" ? "Please select a class" : null, + }, + }); + + const client = useApi(); + const queryClient = useQueryClient(); + + const categories = useQuery({ + queryKey: ["categories"], + queryFn: async () => + await client.get(`/aircraft/categories`).then((res) => res.data), + }); + + const [category, setCategory] = useState(""); + const [classSelection, setClassSelection] = useState(""); + + const classes = useQuery({ + queryKey: ["classes", category], + queryFn: async () => + await client + .get(`/aircraft/class?category=${category}`) + .then((res) => res.data), + enabled: !!category, + }); + + return ( +
onSubmit(values))}> + + + + + + + + + {isError ? ( + + {error instanceof AxiosError + ? error?.response?.data?.detail ?? "Error adding aircraft" + : error?.message} + + ) : isPending ? ( + Adding aircraft... + ) : null} + {withCancelButton ? ( + + ) : null} + + + + +
+ ); +} diff --git a/web/app/ui/form/flight-form.tsx b/web/app/ui/form/flight-form.tsx index 1b04880..7afbf80 100644 --- a/web/app/ui/form/flight-form.tsx +++ b/web/app/ui/form/flight-form.tsx @@ -33,7 +33,7 @@ export default function FlightForm({ }: { onSubmit: (values: FlightFormSchema) => void; isError: boolean; - error: AxiosError | null; + error: Error | null; initialValues?: FlightFormSchema | null; mah?: string; submitButtonLabel?: string; @@ -262,7 +262,9 @@ export default function FlightForm({ {isError ? ( - {error?.message} + {error instanceof AxiosError + ? error.response?.data.detail + : error?.message} ) : null} {withCancelButton ? (