regularVesselInfoForm.tsx
Mon Jun 17 2024 07:18:31 GMT+0000 (Coordinated Universal Time)
Saved by @rafal_rydz
@ -0,0 +1,396 @@
import {
ButtonContent,
DestructiveButton,
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
Icon,
If,
Input,
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
Toaster,
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "ui";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import * as z from "zod";
import React, { useEffect, useState } from "react";
import { toast } from "sonner";
import wretch from "wretch";
export interface VesselInfo {
[key: string]: string | undefined;
}
interface RegularVesselFormProps {
vesselInfo: VesselInfo;
vesselId?: string;
imo?: string;
}
export const formSchema = z.object({
imo: z.string().optional(),
cargoType: z.string().optional(),
cargoSubType: z.string().optional(),
mmsi: z.string().optional(),
vesselName: z.string().optional(),
yearOfBuild: z.string().optional(),
flag: z.string().optional(),
dwt: z.string().optional(),
maximumDraft: z.string().optional(),
geared: z.string().optional(),
gearDetails: z.string().optional(),
});
type FieldsNameHelper = {
[key: string]: { name: string; description: string };
};
export const fieldsNameHelper: FieldsNameHelper = {
imo: {
name: "IMO",
description: "International Maritime Organization identifier",
},
cargoType: {
name: "Cargo Type",
description: "The type of cargo the vessel carries",
},
cargoSubType: {
name: "Cargo Sub Type",
description: "The subtype of cargo the vessel carries",
},
mmsi: { name: "MMSI", description: "Maritime Mobile Service Identity" },
vesselName: { name: "Vessel Name", description: "The name of the vessel" },
yearOfBuild: {
name: "Year of Build",
description: "The year the vessel was built",
},
flag: { name: "Flag", description: "The flag country code" },
dwt: { name: "DWT", description: "Dead Weight Tonnage" },
maximumDraft: {
name: "Maximum Draft",
description:
"The deepest point of the vessel below the waterline when fully loaded",
},
geared: {
name: "Geared",
description: "Indicates if the vessel is geared (yes or no)",
},
gearDetails: {
name: "Gear Details",
description: "Details about the vessel's gear",
},
};
export const numberFields: string[] = [
"dwt",
"yearOfBuild",
"maximumDraft",
"mmsi",
"imo",
];
export const uppercaseFields: string[] = ["imo", "mmsi"];
export function toTitleCase(str: string): string {
if (uppercaseFields.includes(str)) {
return str.toUpperCase().replace("_", " ");
} else {
str = str.replace("_", " ");
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
}
}
export const RegularVesselInfoForm = ({
vesselInfo,
vesselId,
imo,
}: RegularVesselFormProps) => {
const disabledFields: string[] = ["vesselId", "imo"];
const [selectedType, setSelectedType] = useState<string | null>(
vesselInfo?.cargoType ?? null,
);
const defaultFieldsValues = Object.fromEntries(
Object.keys(fieldsNameHelper).map((key) => [
key,
vesselInfo ? vesselInfo[fieldsNameHelper[key].name as string] ?? "" : "",
]),
);
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: defaultFieldsValues,
});
useEffect(() => {
if (vesselInfo) {
form.reset(defaultFieldsValues);
}
}, [vesselInfo]);
async function onSubmit(values: z.infer<typeof formSchema>) {
const updatedVesselInfo: VesselInfo = Object.entries(values).reduce(
(acc: VesselInfo, [key, value]) => {
const vesselInfoKey: string = fieldsNameHelper[key].name;
acc[vesselInfoKey] = (value || "").toString().toLowerCase();
return acc;
},
{},
);
try {
const response = await wretch("/api/form/regularVessel")
.post(updatedVesselInfo)
.res();
if (response.ok) {
await wretch(`/api/form/regularVessel?vessel_id=${vesselId}&imo=${imo}`)
.get()
.json();
toast.success("Success!", {
description: "Vessel details updated.",
});
} else {
toast.error("Error submitting form");
}
} catch (error) {
toast.error("Something went wrong", {
description: (error as any)?.message,
});
}
}
return (
<div className="mt-6 flex w-full flex-col gap-2 p-2 sm:w-1/2">
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
{Object.keys(formSchema.shape).map((key, index) => (
<React.Fragment key={key}>
<If
condition={Object.keys(vesselInfo || {}).includes(
fieldsNameHelper[key].name,
)}
>
<If
condition={
key !== "type" && key !== "subType" && key !== "buildYear"
}
>
<FormField
key={key}
control={form.control}
name={key as any}
render={({ field }) => (
<FormItem className={"flex flex-row items-center"}>
<FormLabel className={"w-64 text-lg font-light"}>
{toTitleCase(fieldsNameHelper[key].name)}
</FormLabel>
<div className={"mr-2"}>
<TooltipProvider>
<Tooltip>
<TooltipTrigger className="text-black hover:text-black/50 dark:text-white dark:hover:text-white/50">
<Icon name="unknown" style="h-5 w-5" />
</TooltipTrigger>
<TooltipContent>
<p>{fieldsNameHelper[key].description}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<FormControl className={"w-full"}>
<Input
{...field}
className={"text-md font-light"}
type={
numberFields.includes(key) ? "number" : "text"
}
value={field.value ?? ""}
disabled={disabledFields.includes(key)}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</If>
<If condition={key === "type"}>
<FormField
control={form.control}
name="type"
render={({ field }) => (
<FormItem className={"flex flex-row items-center"}>
<FormLabel className={"w-64 text-lg font-light"}>
Type
</FormLabel>
<div className={"mr-2"}>
<TooltipProvider>
<Tooltip>
<TooltipTrigger className="text-black hover:text-black/50 dark:text-white dark:hover:text-white/50">
<Icon name="unknown" style="h-5 w-5" />
</TooltipTrigger>
<TooltipContent>
<p>{fieldsNameHelper[key].description}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<Select
onValueChange={(value: any) => {
field.onChange(value);
setSelectedType(value);
}}
value={field.value ?? ""}
>
<FormControl className={"text-md w-full font-light"}>
<SelectTrigger>
<SelectValue placeholder="Select a type" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value={"cargo vessel"}>
Cargo Vessel
</SelectItem>
<SelectItem value={"tanker"}>Tanker</SelectItem>
<SelectItem value={"passenger vessel"}>
Passenger Vessel
</SelectItem>
<SelectItem value={"other"}>Other</SelectItem>
</SelectContent>
</Select>
</FormItem>
)}
/>
</If>
<If condition={key === "subType"}>
<FormField
control={form.control}
name="subType"
render={({ field }) => (
<FormItem className={"flex flex-row items-center"}>
<FormLabel className={"w-64 text-lg font-light"}>
Sub type
</FormLabel>
<div className={"mr-2"}>
<TooltipProvider>
<Tooltip>
<TooltipTrigger className="text-black hover:text-black/50 dark:text-white dark:hover:text-white/50">
<Icon name="unknown" style="h-5 w-5" />
</TooltipTrigger>
<TooltipContent>
<p>{fieldsNameHelper[key].description}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<Select
onValueChange={field.onChange}
value={field.value ?? ""}
>
<FormControl className={"text-md w-full font-light"}>
<SelectTrigger>
<SelectValue placeholder="Select a sub type" />
</SelectTrigger>
</FormControl>
{selectedType && selectedType === "cargo vessel" && (
<SelectContent>
<SelectItem value={"bulk carrier"}>
Bulk Carrier
</SelectItem>
<SelectItem value={"container ship"}>
Container Ship
</SelectItem>
<SelectItem value={"general cargo ship"}>
General Cargo Ship
</SelectItem>
</SelectContent>
)}
{selectedType && selectedType === "tanker" && (
<SelectContent>
<SelectItem value={"oil tanker"}>
Oil Tanker
</SelectItem>
<SelectItem value={"chemical tanker"}>
Chemical Tanker
</SelectItem>
<SelectItem value={"gas carrier"}>
Gas Carrier
</SelectItem>
</SelectContent>
)}
{selectedType &&
selectedType === "passenger vessel" && (
<SelectContent>
<SelectItem value={"cruise ship"}>
Cruise Ship
</SelectItem>
<SelectItem value={"ferry"}>Ferry</SelectItem>
</SelectContent>
)}
</Select>
</FormItem>
)}
/>
</If>
<If condition={key === "buildYear"}>
<FormField
control={form.control}
name="buildYear"
render={({ field }) => (
<FormItem className={"flex flex-row items-center"}>
<FormLabel className={"w-64 text-lg font-light"}>
Build year
</FormLabel>
<div className={"mr-2"}>
<TooltipProvider>
<Tooltip>
<TooltipTrigger className="text-black hover:text-black/50 dark:text-white dark:hover:text-white/50">
<Icon name="unknown" style="h-5 w-5" />
</TooltipTrigger>
<TooltipContent>
<p>{fieldsNameHelper[key].description}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<FormControl className={"w-full"}>
<Input
{...field}
className={"text-md font-light"}
type="number"
min={1900}
max={2100}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</If>
</If>
</React.Fragment>
))}
<If
condition={vesselInfo && Object.keys(formSchema.shape).length > 0}
>
<div className="flex flex-row justify-end">
<DestructiveButton type="submit" className="mt-4">
<ButtonContent>Update</ButtonContent>
</DestructiveButton>
</div>
</If>
<Toaster />
</form>
</Form>
</div>
);
};



Comments