Implement aircraft values in flight creation/updating
This commit is contained in:
parent
d6d03c9027
commit
b50d333677
@ -1,6 +1,7 @@
|
|||||||
import ErrorDisplay from "@/ui/error-display";
|
import ErrorDisplay from "@/ui/error-display";
|
||||||
import AircraftForm from "@/ui/form/aircraft-form";
|
import AircraftForm from "@/ui/form/aircraft-form";
|
||||||
import { useApi } from "@/util/api";
|
import { useApi } from "@/util/api";
|
||||||
|
import { useAircraft } from "@/util/hooks";
|
||||||
import { AircraftFormSchema, AircraftSchema } from "@/util/types";
|
import { AircraftFormSchema, AircraftSchema } from "@/util/types";
|
||||||
import {
|
import {
|
||||||
ActionIcon,
|
ActionIcon,
|
||||||
@ -11,37 +12,19 @@ import {
|
|||||||
Group,
|
Group,
|
||||||
Loader,
|
Loader,
|
||||||
Modal,
|
Modal,
|
||||||
NumberInput,
|
|
||||||
ScrollArea,
|
ScrollArea,
|
||||||
Select,
|
|
||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
|
||||||
Title,
|
Title,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import { useForm } from "@mantine/form";
|
|
||||||
import { randomId, useDisclosure } from "@mantine/hooks";
|
import { randomId, useDisclosure } from "@mantine/hooks";
|
||||||
import { IconPencil, IconPlus, IconTrash, IconX } from "@tabler/icons-react";
|
import { IconPencil, IconPlus, IconTrash, IconX } from "@tabler/icons-react";
|
||||||
import {
|
import {
|
||||||
UseQueryResult,
|
UseQueryResult,
|
||||||
useMutation,
|
useMutation,
|
||||||
useQuery,
|
|
||||||
useQueryClient,
|
useQueryClient,
|
||||||
} from "@tanstack/react-query";
|
} from "@tanstack/react-query";
|
||||||
import { AxiosError } from "axios";
|
|
||||||
import { useState } from "react";
|
|
||||||
|
|
||||||
function useAircraft() {
|
|
||||||
const client = useApi();
|
|
||||||
|
|
||||||
const aircraft = useQuery({
|
|
||||||
queryKey: ["aircraft-list"],
|
|
||||||
queryFn: async () => await client.get(`/aircraft`).then((res) => res.data),
|
|
||||||
});
|
|
||||||
|
|
||||||
return aircraft;
|
|
||||||
}
|
|
||||||
|
|
||||||
function AircraftCard({ aircraft }: { aircraft: AircraftSchema }) {
|
function AircraftCard({ aircraft }: { aircraft: AircraftSchema }) {
|
||||||
const [deleteOpened, { open: openDelete, close: closeDelete }] =
|
const [deleteOpened, { open: openDelete, close: closeDelete }] =
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Container, Stack, Title } from "@mantine/core";
|
import { Center, Container, Loader, Stack, Title } from "@mantine/core";
|
||||||
import {
|
import {
|
||||||
FlightFormSchema,
|
FlightFormSchema,
|
||||||
flightCreateHelper,
|
flightCreateHelper,
|
||||||
@ -9,6 +9,7 @@ import { useApi } from "@/util/api";
|
|||||||
import { useNavigate, useParams } from "@remix-run/react";
|
import { useNavigate, useParams } from "@remix-run/react";
|
||||||
import { AxiosError } from "axios";
|
import { AxiosError } from "axios";
|
||||||
import FlightForm from "@/ui/form/flight-form";
|
import FlightForm from "@/ui/form/flight-form";
|
||||||
|
import ErrorDisplay from "@/ui/error-display";
|
||||||
|
|
||||||
export default function EditFlight() {
|
export default function EditFlight() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
@ -47,16 +48,30 @@ export default function EditFlight() {
|
|||||||
<Stack>
|
<Stack>
|
||||||
<Title order={2}>Edit Flight</Title>
|
<Title order={2}>Edit Flight</Title>
|
||||||
|
|
||||||
<FlightForm
|
{flight.isLoading ? (
|
||||||
initialValues={flightEditHelper(flight.data) ?? null}
|
<Center h="calc(100vh - 95px - 110px)">
|
||||||
onSubmit={editFlight.mutate}
|
<Loader />
|
||||||
isError={editFlight.isError}
|
</Center>
|
||||||
error={editFlight.error}
|
) : flight.isError ? (
|
||||||
submitButtonLabel="Update"
|
<Center h="calc(100vh - 95px - 110px)">
|
||||||
withCancelButton
|
<ErrorDisplay error={flight.error.message} />
|
||||||
cancelFunc={() => navigate(`/logbook/flights/${params.id}`)}
|
</Center>
|
||||||
mah="calc(100vh - 95px - 110px)"
|
) : (
|
||||||
/>
|
<FlightForm
|
||||||
|
initialValues={
|
||||||
|
flight.data ? flightEditHelper(flight.data) ?? null : null
|
||||||
|
}
|
||||||
|
onSubmit={editFlight.mutate}
|
||||||
|
isPending={editFlight.isPending}
|
||||||
|
isError={editFlight.isError}
|
||||||
|
error={editFlight.error}
|
||||||
|
submitButtonLabel="Update"
|
||||||
|
withCancelButton
|
||||||
|
cancelFunc={() => navigate(`/logbook/flights/${params.id}`)}
|
||||||
|
mah="calc(100vh - 95px - 110px)"
|
||||||
|
autofillHobbs={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
@ -33,9 +33,11 @@ export default function NewFlight() {
|
|||||||
|
|
||||||
<FlightForm
|
<FlightForm
|
||||||
onSubmit={createFlight.mutate}
|
onSubmit={createFlight.mutate}
|
||||||
|
isPending={createFlight.isPending}
|
||||||
isError={createFlight.isError}
|
isError={createFlight.isError}
|
||||||
error={createFlight.error}
|
error={createFlight.error}
|
||||||
mah="calc(100vh - 95px - 110px)"
|
mah="calc(100vh - 95px - 110px)"
|
||||||
|
autofillHobbs
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Container>
|
</Container>
|
||||||
|
@ -47,7 +47,7 @@ export default function Index() {
|
|||||||
staleTime: 1000,
|
staleTime: 1000,
|
||||||
retry: (failureCount, error: Error) => {
|
retry: (failureCount, error: Error) => {
|
||||||
return (
|
return (
|
||||||
failureCount < 5 &&
|
failureCount < 3 &&
|
||||||
(!error ||
|
(!error ||
|
||||||
(error instanceof AxiosError &&
|
(error instanceof AxiosError &&
|
||||||
error.response?.status !== 401 &&
|
error.response?.status !== 401 &&
|
||||||
|
@ -12,7 +12,7 @@ import {
|
|||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import { useForm } from "@mantine/form";
|
import { useForm } from "@mantine/form";
|
||||||
import { IconPencil, IconX } from "@tabler/icons-react";
|
import { IconPencil, IconX } from "@tabler/icons-react";
|
||||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { AxiosError } from "axios";
|
import { AxiosError } from "axios";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
|
@ -1,15 +1,23 @@
|
|||||||
import { FlightFormSchema } from "@/util/types";
|
|
||||||
import {
|
import {
|
||||||
|
AircraftFormSchema,
|
||||||
|
AircraftSchema,
|
||||||
|
FlightFormSchema,
|
||||||
|
} from "@/util/types";
|
||||||
|
import {
|
||||||
|
ActionIcon,
|
||||||
Button,
|
Button,
|
||||||
CloseButton,
|
CloseButton,
|
||||||
Container,
|
Container,
|
||||||
Fieldset,
|
Fieldset,
|
||||||
Group,
|
Group,
|
||||||
|
Modal,
|
||||||
NumberInput,
|
NumberInput,
|
||||||
ScrollArea,
|
ScrollArea,
|
||||||
|
Select,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput,
|
||||||
Textarea,
|
Textarea,
|
||||||
|
Tooltip,
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import { DatePickerInput } from "@mantine/dates";
|
import { DatePickerInput } from "@mantine/dates";
|
||||||
import { useForm } from "@mantine/form";
|
import { useForm } from "@mantine/form";
|
||||||
@ -18,11 +26,18 @@ import { HourInput, ZeroHourInput } from "./hour-input";
|
|||||||
import TimeInput from "./time-input";
|
import TimeInput from "./time-input";
|
||||||
import { ZeroIntInput } from "./int-input";
|
import { ZeroIntInput } from "./int-input";
|
||||||
import ListInput from "./list-input";
|
import ListInput from "./list-input";
|
||||||
import { IconPencil } from "@tabler/icons-react";
|
import { IconPencil, IconPlaneTilt, IconPlus } from "@tabler/icons-react";
|
||||||
import { AxiosError } from "axios";
|
import { AxiosError } from "axios";
|
||||||
|
import { useDisclosure } from "@mantine/hooks";
|
||||||
|
import AircraftForm from "./aircraft-form";
|
||||||
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
|
import { useApi } from "@/util/api";
|
||||||
|
import { useAircraft } from "@/util/hooks";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
export default function FlightForm({
|
export default function FlightForm({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
|
isPending,
|
||||||
isError,
|
isError,
|
||||||
error,
|
error,
|
||||||
initialValues,
|
initialValues,
|
||||||
@ -30,8 +45,10 @@ export default function FlightForm({
|
|||||||
submitButtonLabel,
|
submitButtonLabel,
|
||||||
withCancelButton,
|
withCancelButton,
|
||||||
cancelFunc,
|
cancelFunc,
|
||||||
|
autofillHobbs = false,
|
||||||
}: {
|
}: {
|
||||||
onSubmit: (values: FlightFormSchema) => void;
|
onSubmit: (values: FlightFormSchema) => void;
|
||||||
|
isPending: boolean;
|
||||||
isError: boolean;
|
isError: boolean;
|
||||||
error: Error | null;
|
error: Error | null;
|
||||||
initialValues?: FlightFormSchema | null;
|
initialValues?: FlightFormSchema | null;
|
||||||
@ -39,6 +56,7 @@ export default function FlightForm({
|
|||||||
submitButtonLabel?: string;
|
submitButtonLabel?: string;
|
||||||
withCancelButton?: boolean;
|
withCancelButton?: boolean;
|
||||||
cancelFunc?: () => void;
|
cancelFunc?: () => void;
|
||||||
|
autofillHobbs?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const form = useForm<FlightFormSchema>({
|
const form = useForm<FlightFormSchema>({
|
||||||
initialValues: initialValues ?? {
|
initialValues: initialValues ?? {
|
||||||
@ -86,196 +104,399 @@ export default function FlightForm({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [aircraftOpened, { open: openAircraft, close: closeAircraft }] =
|
||||||
|
useDisclosure(false);
|
||||||
|
|
||||||
|
const client = useApi();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
const addAircraft = useMutation({
|
||||||
|
mutationFn: async (values: AircraftFormSchema) => {
|
||||||
|
const newAircraft = values;
|
||||||
|
if (newAircraft) {
|
||||||
|
const res = await client.post("/aircraft", newAircraft);
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
throw new Error("Aircraft creation failed");
|
||||||
|
},
|
||||||
|
onSuccess: async () => {
|
||||||
|
await queryClient.invalidateQueries({ queryKey: ["aircraft-list"] });
|
||||||
|
close();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const [aircraft, setAircraft] = useState<string | null>(
|
||||||
|
initialValues?.aircraft ?? ""
|
||||||
|
);
|
||||||
|
|
||||||
|
const [hobbsTouched, setHobbsTouched] = useState(false);
|
||||||
|
|
||||||
|
const getHobbs = useQuery({
|
||||||
|
queryKey: ["hobbs", aircraft],
|
||||||
|
queryFn: async () =>
|
||||||
|
await client.get(`/aircraft/tail/${aircraft}`).then((res) => res.data),
|
||||||
|
enabled: !!aircraft && aircraft !== "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const getAircraft = useAircraft();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (autofillHobbs && getHobbs.isFetched && getHobbs.data && !hobbsTouched) {
|
||||||
|
form.setFieldValue(
|
||||||
|
"hobbs_start",
|
||||||
|
getHobbs.data.hobbs ?? form.getTransformedValues()["hobbs_start"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [getHobbs.data]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={form.onSubmit((values) => onSubmit(values))}>
|
<>
|
||||||
<ScrollArea.Autosize mah={mah}>
|
<Modal
|
||||||
<Container>
|
opened={aircraftOpened}
|
||||||
{/* Date and Aircraft */}
|
onClose={closeAircraft}
|
||||||
|
title="New Aircraft"
|
||||||
|
centered
|
||||||
|
>
|
||||||
|
<AircraftForm
|
||||||
|
onSubmit={addAircraft.mutate}
|
||||||
|
isError={addAircraft.isError}
|
||||||
|
error={addAircraft.error}
|
||||||
|
isPending={addAircraft.isPending}
|
||||||
|
submitButtonLabel="Add"
|
||||||
|
withCancelButton
|
||||||
|
cancelFunc={closeAircraft}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
<form onSubmit={form.onSubmit((values) => onSubmit(values))}>
|
||||||
|
<ScrollArea.Autosize mah={mah}>
|
||||||
|
<Container>
|
||||||
|
{/* Date and Aircraft */}
|
||||||
|
|
||||||
<Fieldset>
|
<Fieldset>
|
||||||
<Group justify="center" grow>
|
<Group justify="center" grow>
|
||||||
<DatePickerInput label="Date" {...form.getInputProps("date")} />
|
<DatePickerInput
|
||||||
<TextInput label="Aircraft" {...form.getInputProps("aircraft")} />
|
label="Date"
|
||||||
</Group>
|
{...form.getInputProps("date")}
|
||||||
</Fieldset>
|
withAsterisk
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
label={
|
||||||
|
<Group gap="0">
|
||||||
|
<Text size="sm" fw={700} span>
|
||||||
|
Aircraft
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
pl="0.3rem"
|
||||||
|
style={{ color: "var(--mantine-color-error)" }}
|
||||||
|
span
|
||||||
|
>
|
||||||
|
*
|
||||||
|
</Text>
|
||||||
|
|
||||||
{/* Route */}
|
<Tooltip label="Add Aircraft">
|
||||||
|
<ActionIcon
|
||||||
|
variant="transparent"
|
||||||
|
onClick={openAircraft}
|
||||||
|
>
|
||||||
|
<IconPlus size="1rem" />
|
||||||
|
</ActionIcon>
|
||||||
|
</Tooltip>
|
||||||
|
</Group>
|
||||||
|
}
|
||||||
|
data={
|
||||||
|
getAircraft.isFetched
|
||||||
|
? getAircraft.data?.map((item: AircraftSchema) => ({
|
||||||
|
value: item.tail_no,
|
||||||
|
label: item.tail_no,
|
||||||
|
}))
|
||||||
|
: initialValues
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
value: initialValues?.aircraft,
|
||||||
|
label: initialValues?.aircraft,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
value={aircraft}
|
||||||
|
{...form.getInputProps("aircraft")}
|
||||||
|
onChange={(_value, option) => {
|
||||||
|
form.setFieldValue("aircraft", option.label);
|
||||||
|
setAircraft(option.label);
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: ["hobbs", aircraft],
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
</Fieldset>
|
||||||
|
|
||||||
<Fieldset legend="Route" mt="lg">
|
{/* Route */}
|
||||||
<Group justify="center" grow>
|
|
||||||
|
<Fieldset legend="Route" mt="lg">
|
||||||
|
<Group justify="center" grow>
|
||||||
|
<TextInput
|
||||||
|
label="Waypoint From"
|
||||||
|
{...form.getInputProps("waypoint_from")}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
label="Waypoint To"
|
||||||
|
{...form.getInputProps("waypoint_to")}
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Waypoint From"
|
label="Route"
|
||||||
{...form.getInputProps("waypoint_from")}
|
{...form.getInputProps("route")}
|
||||||
|
mt="md"
|
||||||
/>
|
/>
|
||||||
<TextInput
|
</Fieldset>
|
||||||
label="Waypoint To"
|
|
||||||
{...form.getInputProps("waypoint_to")}
|
{/* Times */}
|
||||||
|
|
||||||
|
<Fieldset legend="Times" mt="md">
|
||||||
|
<Group justify="center" grow>
|
||||||
|
<NumberInput
|
||||||
|
label={
|
||||||
|
<Group gap="0">
|
||||||
|
<Text size="sm" fw={700} span>
|
||||||
|
Hobbs Start
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Tooltip
|
||||||
|
label={
|
||||||
|
getHobbs.isFetched &&
|
||||||
|
getHobbs.data &&
|
||||||
|
getHobbs.data.hobbs ===
|
||||||
|
form.getTransformedValues()["hobbs_start"]
|
||||||
|
? "Using aircraft time"
|
||||||
|
: "Use Aircraft Time"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ActionIcon
|
||||||
|
variant="transparent"
|
||||||
|
disabled={
|
||||||
|
!(
|
||||||
|
getHobbs.isFetched &&
|
||||||
|
getHobbs.data &&
|
||||||
|
getHobbs.data.hobbs !==
|
||||||
|
form.getTransformedValues()["hobbs_start"]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
style={
|
||||||
|
!(
|
||||||
|
getHobbs.isFetched &&
|
||||||
|
getHobbs.data &&
|
||||||
|
getHobbs.data.hobbs !==
|
||||||
|
form.getTransformedValues()["hobbs_start"]
|
||||||
|
)
|
||||||
|
? { backgroundColor: "transparent" }
|
||||||
|
: {}
|
||||||
|
}
|
||||||
|
onClick={() =>
|
||||||
|
form.setFieldValue(
|
||||||
|
"hobbs_start",
|
||||||
|
getHobbs.data?.hobbs ?? 0.0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<IconPlaneTilt size="1rem" />
|
||||||
|
</ActionIcon>
|
||||||
|
</Tooltip>
|
||||||
|
</Group>
|
||||||
|
}
|
||||||
|
decimalScale={1}
|
||||||
|
step={0.1}
|
||||||
|
min={0}
|
||||||
|
fixedDecimalScale
|
||||||
|
leftSection={
|
||||||
|
<CloseButton
|
||||||
|
aria-label="Clear input"
|
||||||
|
onClick={() => form.setFieldValue("hobbs_start", "")}
|
||||||
|
style={{
|
||||||
|
display:
|
||||||
|
["", null].indexOf(
|
||||||
|
form.getTransformedValues()["hobbs_start"]
|
||||||
|
) > -1
|
||||||
|
? "none"
|
||||||
|
: undefined,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{...form.getInputProps("hobbs_start")}
|
||||||
|
onChange={(e) => {
|
||||||
|
form.setFieldValue("hobbs_start", e);
|
||||||
|
setHobbsTouched(true);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<HourInput form={form} field="hobbs_end" label="Hobbs End" />
|
||||||
|
</Group>
|
||||||
|
</Fieldset>
|
||||||
|
|
||||||
|
{/* Start/Stop */}
|
||||||
|
|
||||||
|
<Fieldset legend="Start/Stop" mt="md">
|
||||||
|
<Group justify="center" grow>
|
||||||
|
<TimeInput form={form} field="time_start" label="Start Time" />
|
||||||
|
<TimeInput form={form} field="time_off" label="Time Off" />
|
||||||
|
</Group>
|
||||||
|
<Group justify="center" grow mt="md">
|
||||||
|
<TimeInput form={form} field="time_down" label="Time Down" />
|
||||||
|
<TimeInput form={form} field="time_stop" label="Stop Time" />
|
||||||
|
</Group>
|
||||||
|
</Fieldset>
|
||||||
|
|
||||||
|
{/* Hours */}
|
||||||
|
|
||||||
|
<Fieldset legend="Hours" mt="md">
|
||||||
|
<Group justify="center" grow>
|
||||||
|
<ZeroHourInput
|
||||||
|
form={form}
|
||||||
|
field="time_total"
|
||||||
|
label="Time Total"
|
||||||
|
/>
|
||||||
|
<ZeroHourInput form={form} field="time_pic" label="Time PIC" />
|
||||||
|
<ZeroHourInput form={form} field="time_sic" label="Time SIC" />
|
||||||
|
</Group>
|
||||||
|
<Group justify="center" grow mt="md">
|
||||||
|
<ZeroHourInput
|
||||||
|
form={form}
|
||||||
|
field="time_night"
|
||||||
|
label="Time Night"
|
||||||
|
/>
|
||||||
|
<ZeroHourInput
|
||||||
|
form={form}
|
||||||
|
field="time_solo"
|
||||||
|
label="Time Solo"
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
</Fieldset>
|
||||||
|
|
||||||
|
{/* Cross-Country */}
|
||||||
|
|
||||||
|
<Fieldset legend="Cross-Country" mt="md">
|
||||||
|
<Group justify="center" grow>
|
||||||
|
<ZeroHourInput form={form} field="time_xc" label="Hours" />
|
||||||
|
<NumberInput
|
||||||
|
label="Distance"
|
||||||
|
decimalScale={1}
|
||||||
|
min={0}
|
||||||
|
fixedDecimalScale
|
||||||
|
leftSection={
|
||||||
|
<CloseButton
|
||||||
|
aria-label="Clear input"
|
||||||
|
onClick={() => form.setFieldValue("dist_xc", 0)}
|
||||||
|
style={{
|
||||||
|
display:
|
||||||
|
form.getTransformedValues().dist_xc == 0
|
||||||
|
? "none"
|
||||||
|
: undefined,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{...form.getInputProps("dist_xc")}
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
</Fieldset>
|
||||||
|
|
||||||
|
{/* Landings */}
|
||||||
|
|
||||||
|
<Fieldset legend="Landings" mt="md">
|
||||||
|
<Group justify="center" grow>
|
||||||
|
<ZeroIntInput form={form} field="landings_day" label="Day" />
|
||||||
|
<ZeroIntInput
|
||||||
|
form={form}
|
||||||
|
field="landings_night"
|
||||||
|
label="Night"
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
</Fieldset>
|
||||||
|
|
||||||
|
{/* Instrument */}
|
||||||
|
|
||||||
|
<Fieldset legend="Instrument" mt="md">
|
||||||
|
<Group justify="center" grow>
|
||||||
|
<ZeroHourInput
|
||||||
|
form={form}
|
||||||
|
field="time_instrument"
|
||||||
|
label="Time Instrument"
|
||||||
|
/>
|
||||||
|
<ZeroHourInput
|
||||||
|
form={form}
|
||||||
|
field="time_sim_instrument"
|
||||||
|
label="Time Sim Instrument"
|
||||||
|
/>
|
||||||
|
<ZeroIntInput
|
||||||
|
form={form}
|
||||||
|
field="holds_instrument"
|
||||||
|
label="Instrument Holds"
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
</Fieldset>
|
||||||
|
|
||||||
|
{/* Instruction */}
|
||||||
|
|
||||||
|
<Fieldset legend="Instruction" mt="md">
|
||||||
|
<Group justify="center" grow>
|
||||||
|
<ZeroHourInput
|
||||||
|
form={form}
|
||||||
|
field="dual_given"
|
||||||
|
label="Dual Given"
|
||||||
|
/>
|
||||||
|
<ZeroHourInput
|
||||||
|
form={form}
|
||||||
|
field="dual_recvd"
|
||||||
|
label="Dual Received"
|
||||||
|
/>
|
||||||
|
<ZeroHourInput form={form} field="time_sim" label="Sim Time" />
|
||||||
|
<ZeroHourInput
|
||||||
|
form={form}
|
||||||
|
field="time_ground"
|
||||||
|
label="Ground Time"
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
</Fieldset>
|
||||||
|
|
||||||
|
{/* About the Flight */}
|
||||||
|
|
||||||
|
<Fieldset legend="About" mt="md">
|
||||||
|
<ListInput form={form} field="tags" label="Tags" />
|
||||||
|
<Group justify="center" grow mt="md">
|
||||||
|
<ListInput form={form} field="pax" label="Pax" />
|
||||||
|
<ListInput form={form} field="crew" label="Crew" />
|
||||||
|
</Group>
|
||||||
|
<Textarea
|
||||||
|
label="Comments"
|
||||||
|
mt="md"
|
||||||
|
autosize
|
||||||
|
minRows={4}
|
||||||
|
{...form.getInputProps("comments")}
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Fieldset>
|
||||||
<TextInput label="Route" {...form.getInputProps("route")} mt="md" />
|
</Container>
|
||||||
</Fieldset>
|
</ScrollArea.Autosize>
|
||||||
|
|
||||||
{/* Times */}
|
<Group justify="flex-end" mt="md">
|
||||||
|
{isPending ? (
|
||||||
<Fieldset legend="Times" mt="md">
|
<Text c="yellow" fw={700}>
|
||||||
<Group justify="center" grow>
|
Loading...
|
||||||
<HourInput form={form} field="hobbs_start" label="Hobbs Start" />
|
</Text>
|
||||||
<HourInput form={form} field="hobbs_end" label="Hobbs End" />
|
) : isError ? (
|
||||||
</Group>
|
<Text c="red" fw={700}>
|
||||||
</Fieldset>
|
{error instanceof AxiosError
|
||||||
|
? error.response?.data.detail
|
||||||
{/* Start/Stop */}
|
: error?.message}
|
||||||
|
</Text>
|
||||||
<Fieldset legend="Start/Stop" mt="md">
|
) : null}
|
||||||
<Group justify="center" grow>
|
{withCancelButton ? (
|
||||||
<TimeInput form={form} field="time_start" label="Start Time" />
|
<Button onClick={cancelFunc} color="gray">
|
||||||
<TimeInput form={form} field="time_off" label="Time Off" />
|
Cancel
|
||||||
</Group>
|
</Button>
|
||||||
<Group justify="center" grow mt="md">
|
) : null}
|
||||||
<TimeInput form={form} field="time_down" label="Time Down" />
|
<Button type="submit" leftSection={<IconPencil />}>
|
||||||
<TimeInput form={form} field="time_stop" label="Stop Time" />
|
{submitButtonLabel ?? "Create"}
|
||||||
</Group>
|
|
||||||
</Fieldset>
|
|
||||||
|
|
||||||
{/* Hours */}
|
|
||||||
|
|
||||||
<Fieldset legend="Hours" mt="md">
|
|
||||||
<Group justify="center" grow>
|
|
||||||
<ZeroHourInput
|
|
||||||
form={form}
|
|
||||||
field="time_total"
|
|
||||||
label="Time Total"
|
|
||||||
/>
|
|
||||||
<ZeroHourInput form={form} field="time_pic" label="Time PIC" />
|
|
||||||
<ZeroHourInput form={form} field="time_sic" label="Time SIC" />
|
|
||||||
</Group>
|
|
||||||
<Group justify="center" grow mt="md">
|
|
||||||
<ZeroHourInput
|
|
||||||
form={form}
|
|
||||||
field="time_night"
|
|
||||||
label="Time Night"
|
|
||||||
/>
|
|
||||||
<ZeroHourInput form={form} field="time_solo" label="Time Solo" />
|
|
||||||
</Group>
|
|
||||||
</Fieldset>
|
|
||||||
|
|
||||||
{/* Cross-Country */}
|
|
||||||
|
|
||||||
<Fieldset legend="Cross-Country" mt="md">
|
|
||||||
<Group justify="center" grow>
|
|
||||||
<ZeroHourInput form={form} field="time_xc" label="Hours" />
|
|
||||||
<NumberInput
|
|
||||||
label="Distance"
|
|
||||||
decimalScale={1}
|
|
||||||
min={0}
|
|
||||||
fixedDecimalScale
|
|
||||||
leftSection={
|
|
||||||
<CloseButton
|
|
||||||
aria-label="Clear input"
|
|
||||||
onClick={() => form.setFieldValue("dist_xc", 0)}
|
|
||||||
style={{
|
|
||||||
display:
|
|
||||||
form.getTransformedValues().dist_xc == 0
|
|
||||||
? "none"
|
|
||||||
: undefined,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{...form.getInputProps("dist_xc")}
|
|
||||||
/>
|
|
||||||
</Group>
|
|
||||||
</Fieldset>
|
|
||||||
|
|
||||||
{/* Landings */}
|
|
||||||
|
|
||||||
<Fieldset legend="Landings" mt="md">
|
|
||||||
<Group justify="center" grow>
|
|
||||||
<ZeroIntInput form={form} field="landings_day" label="Day" />
|
|
||||||
<ZeroIntInput form={form} field="landings_night" label="Night" />
|
|
||||||
</Group>
|
|
||||||
</Fieldset>
|
|
||||||
|
|
||||||
{/* Instrument */}
|
|
||||||
|
|
||||||
<Fieldset legend="Instrument" mt="md">
|
|
||||||
<Group justify="center" grow>
|
|
||||||
<ZeroHourInput
|
|
||||||
form={form}
|
|
||||||
field="time_instrument"
|
|
||||||
label="Time Instrument"
|
|
||||||
/>
|
|
||||||
<ZeroHourInput
|
|
||||||
form={form}
|
|
||||||
field="time_sim_instrument"
|
|
||||||
label="Time Sim Instrument"
|
|
||||||
/>
|
|
||||||
<ZeroIntInput
|
|
||||||
form={form}
|
|
||||||
field="holds_instrument"
|
|
||||||
label="Instrument Holds"
|
|
||||||
/>
|
|
||||||
</Group>
|
|
||||||
</Fieldset>
|
|
||||||
|
|
||||||
{/* Instruction */}
|
|
||||||
|
|
||||||
<Fieldset legend="Instruction" mt="md">
|
|
||||||
<Group justify="center" grow>
|
|
||||||
<ZeroHourInput
|
|
||||||
form={form}
|
|
||||||
field="dual_given"
|
|
||||||
label="Dual Given"
|
|
||||||
/>
|
|
||||||
<ZeroHourInput
|
|
||||||
form={form}
|
|
||||||
field="dual_recvd"
|
|
||||||
label="Dual Received"
|
|
||||||
/>
|
|
||||||
<ZeroHourInput form={form} field="time_sim" label="Sim Time" />
|
|
||||||
<ZeroHourInput
|
|
||||||
form={form}
|
|
||||||
field="time_ground"
|
|
||||||
label="Ground Time"
|
|
||||||
/>
|
|
||||||
</Group>
|
|
||||||
</Fieldset>
|
|
||||||
|
|
||||||
{/* About the Flight */}
|
|
||||||
|
|
||||||
<Fieldset legend="About" mt="md">
|
|
||||||
<ListInput form={form} field="tags" label="Tags" />
|
|
||||||
<Group justify="center" grow mt="md">
|
|
||||||
<ListInput form={form} field="pax" label="Pax" />
|
|
||||||
<ListInput form={form} field="crew" label="Crew" />
|
|
||||||
</Group>
|
|
||||||
<Textarea
|
|
||||||
label="Comments"
|
|
||||||
mt="md"
|
|
||||||
autosize
|
|
||||||
minRows={4}
|
|
||||||
{...form.getInputProps("comments")}
|
|
||||||
/>
|
|
||||||
</Fieldset>
|
|
||||||
</Container>
|
|
||||||
</ScrollArea.Autosize>
|
|
||||||
|
|
||||||
<Group justify="flex-end" mt="md">
|
|
||||||
{isError ? (
|
|
||||||
<Text c="red" fw={700}>
|
|
||||||
{error instanceof AxiosError
|
|
||||||
? error.response?.data.detail
|
|
||||||
: error?.message}
|
|
||||||
</Text>
|
|
||||||
) : null}
|
|
||||||
{withCancelButton ? (
|
|
||||||
<Button onClick={cancelFunc} color="gray">
|
|
||||||
Cancel
|
|
||||||
</Button>
|
</Button>
|
||||||
) : null}
|
</Group>
|
||||||
<Button type="submit" leftSection={<IconPencil />}>
|
</form>
|
||||||
{submitButtonLabel ?? "Create"}
|
</>
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
</form>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
13
web/app/util/hooks.ts
Normal file
13
web/app/util/hooks.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { useApi } from "./api";
|
||||||
|
|
||||||
|
export function useAircraft() {
|
||||||
|
const client = useApi();
|
||||||
|
|
||||||
|
const aircraft = useQuery({
|
||||||
|
queryKey: ["aircraft-list"],
|
||||||
|
queryFn: async () => await client.get(`/aircraft`).then((res) => res.data),
|
||||||
|
});
|
||||||
|
|
||||||
|
return aircraft;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user