Display images on flight logs

This commit is contained in:
april
2024-01-15 09:52:56 -06:00
parent a1b5332910
commit 4b80593aa3
8 changed files with 232 additions and 53 deletions

View File

@@ -0,0 +1,91 @@
import { useApi } from "@/util/api";
import { Center, Image, Loader, Modal } from "@mantine/core";
import { UseQueryResult, useQuery } from "@tanstack/react-query";
import ErrorDisplay from "../error-display";
import { useDisclosure } from "@mantine/hooks";
function blobToBase64(blob: Blob): Promise<string | null> {
return new Promise((resolve) => {
const reader = new FileReader();
reader.readAsBinaryString(blob);
reader.onloadend = function () {
if (typeof reader.result === "string") {
const base64 = btoa(reader.result);
resolve(base64);
} else {
resolve(null);
}
};
});
}
function useFetchImageAsBase64(
img_id: string
): UseQueryResult<{ blob: string | null; type: string }> {
const client = useApi();
return useQuery({
queryKey: ["image", img_id],
queryFn: async (): Promise<{
blob: string;
type: string;
}> => {
const response = await client.get(`/img/${img_id}`, {
responseType: "arraybuffer",
});
const blob = (await blobToBase64(new Blob([response.data]))) as string;
const type = (response.headers["content-type"] as string) ?? "image/jpeg";
return { blob, type };
},
});
}
export default function SecureImage({
id,
radius = "sm",
clickable = true,
}: {
id: string;
radius?: string;
clickable?: boolean;
}) {
const { isLoading, error, data } = useFetchImageAsBase64(id);
const [opened, { open, close }] = useDisclosure(false);
if (isLoading)
return (
<Center h="100%">
<Loader />
</Center>
);
if (error) return <ErrorDisplay error="Failed to load image" />;
return (
<>
{clickable ? (
<Modal
title="Image"
opened={opened}
onClose={close}
centered
size="auto"
>
<Image src={`data:${data?.type};base64,${data?.blob}`} />
</Modal>
) : null}
<Image
src={`data:${data?.type};base64,${data?.blob}`}
radius={radius}
onClick={() => {
if (clickable) {
open();
}
}}
/>
</>
);
}

View File

@@ -337,12 +337,32 @@ export default function FlightForm({
<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" />
<TimeInput
form={form}
field="time_start"
label="Start Time"
allowLeadingZeros
/>
<TimeInput
form={form}
field="time_off"
label="Time Off"
allowLeadingZeros
/>
</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" />
<TimeInput
form={form}
field="time_down"
label="Time Down"
allowLeadingZeros
/>
<TimeInput
form={form}
field="time_stop"
label="Stop Time"
allowLeadingZeros
/>
</Group>
</Fieldset>

View File

@@ -8,10 +8,12 @@ export default function TimeInput({
form,
label,
field,
allowLeadingZeros = false,
}: {
form: UseFormReturnType<FlightFormSchema>;
field: string;
label: string;
allowLeadingZeros?: boolean;
}) {
const field_key = field as keyof typeof form.getTransformedValues;
@@ -21,6 +23,7 @@ export default function TimeInput({
allowDecimal={false}
min={0}
max={2359}
allowLeadingZeros={allowLeadingZeros}
leftSection={
<CloseButton
aria-label="Clear input"