From 924252b38f716eb2f45b5ee9d63c8505cbb55f33 Mon Sep 17 00:00:00 2001 From: april Date: Mon, 15 Jan 2024 16:33:26 -0600 Subject: [PATCH] Implement inline editing and image upload/delete/edit --- web/app/routes/logbook.flights.$id/route.tsx | 122 ++++++++----- .../routes/logbook.flights.edit.$id/route.tsx | 37 +++- .../ui/display/editable/aircraft-log-item.tsx | 170 ++++++++++++++++++ web/app/ui/display/editable/date-log-item.tsx | 105 +++++++++++ web/app/ui/display/editable/hour-log-item.tsx | 99 ++++++++++ web/app/ui/display/editable/int-log-item.tsx | 99 ++++++++++ web/app/ui/display/editable/list-log-item.tsx | 115 ++++++++++++ web/app/ui/display/editable/text-log-item.tsx | 88 +++++++++ web/app/ui/display/editable/time-log-item.tsx | 120 +++++++++++++ web/app/ui/form/flight-form.tsx | 13 ++ web/app/ui/form/list-input.tsx | 22 ++- web/app/ui/input/hour-input.tsx | 71 ++++++++ web/app/ui/input/int-input.tsx | 65 +++++++ web/app/ui/input/list-input.tsx | 54 ++++++ web/app/ui/input/time-input.tsx | 53 ++++++ web/app/util/hooks.ts | 23 ++- web/app/util/types.ts | 7 +- 17 files changed, 1213 insertions(+), 50 deletions(-) create mode 100644 web/app/ui/display/editable/aircraft-log-item.tsx create mode 100644 web/app/ui/display/editable/date-log-item.tsx create mode 100644 web/app/ui/display/editable/hour-log-item.tsx create mode 100644 web/app/ui/display/editable/int-log-item.tsx create mode 100644 web/app/ui/display/editable/list-log-item.tsx create mode 100644 web/app/ui/display/editable/text-log-item.tsx create mode 100644 web/app/ui/display/editable/time-log-item.tsx create mode 100644 web/app/ui/input/hour-input.tsx create mode 100644 web/app/ui/input/int-input.tsx create mode 100644 web/app/ui/input/list-input.tsx create mode 100644 web/app/ui/input/time-input.tsx diff --git a/web/app/routes/logbook.flights.$id/route.tsx b/web/app/routes/logbook.flights.$id/route.tsx index 0068f47..22c9b2c 100644 --- a/web/app/routes/logbook.flights.$id/route.tsx +++ b/web/app/routes/logbook.flights.$id/route.tsx @@ -26,6 +26,13 @@ import { useMutation, useQuery } from "@tanstack/react-query"; import { useEffect, useState } from "react"; import classes from "./route.module.css"; +import { AircraftLogItem } from "@/ui/display/editable/aircraft-log-item"; +import { DateLogItem } from "@/ui/display/editable/date-log-item"; +import { HourLogItem } from "@/ui/display/editable/hour-log-item"; +import { IntLogItem } from "@/ui/display/editable/int-log-item"; +import { ListLogItem } from "@/ui/display/editable/list-log-item"; +import { TimeLogItem } from "@/ui/display/editable/time-log-item"; +import { TextLogItem } from "@/ui/display/editable/text-log-item"; export default function Flight() { const params = useParams(); @@ -155,43 +162,55 @@ export default function Flight() { ) : null} - - + {(log.pax || log.crew) && (log.pax.length > 0 || log.crew.length > 0) ? ( - - ) : null} {log.tags && log.tags.length > 0 ? ( - ) : null} {log.comments?.length > 0 ? ( - ) : null} @@ -223,15 +242,17 @@ export default function Flight() { {log.hobbs_start || log.hobbs_end ? ( - - @@ -243,29 +264,37 @@ export default function Flight() { {log.time_start || log.time_off ? ( - - ) : null} {log.time_down || log.time_stop ? ( - - ) : null} @@ -273,32 +302,37 @@ export default function Flight() { ) : null} - - - - - @@ -309,10 +343,11 @@ export default function Flight() { mt="sm" > - - - @@ -339,19 +378,22 @@ export default function Flight() { log.holds_instrument ? ( - - - diff --git a/web/app/routes/logbook.flights.edit.$id/route.tsx b/web/app/routes/logbook.flights.edit.$id/route.tsx index 3b583ad..15e1420 100644 --- a/web/app/routes/logbook.flights.edit.$id/route.tsx +++ b/web/app/routes/logbook.flights.edit.$id/route.tsx @@ -29,7 +29,42 @@ export default function EditFlight() { mutationFn: async (values: FlightFormSchema) => { const newFlight = flightCreateHelper(values); if (newFlight) { - const res = await client.put(`/flights/${params.id}`, newFlight); + const existing_img = values.existing_images ?? []; + const missing = flight.data.images.filter( + (item: string) => existing_img?.indexOf(item) < 0 + ); + + for (const img of missing) { + await client.delete(`/img/${img}`); + } + + const res = await client.put(`/flights/${params.id}`, { + ...newFlight, + images: values.existing_images, + }); + + // Upload images + if (values.images.length > 0) { + const imageForm = new FormData(); + + for (const img of values.images ?? []) { + imageForm.append("images", img); + } + + console.log(imageForm); + + const img_id = await client.post( + `/flights/${params.id}/add_images`, + imageForm, + { headers: { "Content-Type": "multipart/form-data" } } + ); + + if (!img_id) { + await queryClient.invalidateQueries({ queryKey: ["flights-list"] }); + throw new Error("Image upload failed"); + } + } + return res.data; } throw new Error("Flight updating failed"); diff --git a/web/app/ui/display/editable/aircraft-log-item.tsx b/web/app/ui/display/editable/aircraft-log-item.tsx new file mode 100644 index 0000000..c6d0610 --- /dev/null +++ b/web/app/ui/display/editable/aircraft-log-item.tsx @@ -0,0 +1,170 @@ +import AircraftForm from "@/ui/form/aircraft-form"; +import { useApi } from "@/util/api"; +import { useAircraft, usePatchFlight } from "@/util/hooks"; +import { AircraftFormSchema, AircraftSchema } from "@/util/types"; +import { + ActionIcon, + Group, + Tooltip, + Text, + Select, + Modal, + Card, + Stack, + Button, + Loader, + UnstyledButton, +} from "@mantine/core"; +import { useDisclosure } from "@mantine/hooks"; +import { IconPlus, IconPencil, IconX } from "@tabler/icons-react"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { useState } from "react"; + +export function AircraftLogItem({ + label, + content, + id = "", + field = "", +}: { + label: string; + content: string | null; + id?: string; + field?: string; +}) { + const [editValue, setEditValue] = useState(content ?? ""); + const [editError, setEditError] = useState(""); + + const [editOpened, { open: openEdit, close: closeEdit }] = + useDisclosure(false); + + 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 getAircraft = useAircraft(); + + const updateValue = usePatchFlight(id, field, closeEdit); + + if (content === null) content = ""; + const editForm = ( +