import type { ActionFunctionArgs, LoaderFunctionArgs, MetaFunction } from "@remix-run/node"; import { json, redirect } from "@remix-run/node"; import { Form, useActionData, useLoaderData, useNavigation } from "@remix-run/react"; import { requireAuthLevel } from "~/utils/auth.server"; import DashboardLayout from "~/components/DashboardLayout"; import FormModal from "~/components/FormModal"; import Toast from "~/components/Toast"; import { useState, useEffect } from "react"; import { prisma } from "~/utils/db.server"; export const meta: MetaFunction = () => [{ title: "Dredger Locations Management - Phosphat Report" }]; export const loader = async ({ request }: LoaderFunctionArgs) => { const user = await requireAuthLevel(request, 2); const dredgerLocations = await prisma.dredgerLocation.findMany({ orderBy: { name: 'asc' }, include: { _count: { select: { reports: true } } } }); return json({ user, dredgerLocations }); }; export const action = async ({ request }: ActionFunctionArgs) => { await requireAuthLevel(request, 2); const formData = await request.formData(); const intent = formData.get("intent"); const id = formData.get("id"); const name = formData.get("name"); const classType = formData.get("class"); if (intent === "create") { if (typeof name !== "string" || name.length === 0) { return json({ errors: { name: "Name is required" } }, { status: 400 }); } // if (typeof classType !== "string" || !["s", "d", "sp"].includes(classType)) { // return json({ errors: { class: "Valid class is required (s, d, or sp)" } }, { status: 400 }); // } try { await prisma.dredgerLocation.create({ data: { name, class: classType } }); return json({ success: "Dredger location created successfully!" }); } catch (error) { return json({ errors: { form: "Dredger location name already exists" } }, { status: 400 }); } } if (intent === "update") { if (typeof name !== "string" || name.length === 0) { return json({ errors: { name: "Name is required" } }, { status: 400 }); } if (typeof classType !== "string" || !["s", "d", "sp"].includes(classType)) { return json({ errors: { class: "Valid class is required (s, d, or sp)" } }, { status: 400 }); } if (typeof id !== "string") { return json({ errors: { form: "Invalid dredger location ID" } }, { status: 400 }); } try { await prisma.dredgerLocation.update({ where: { id: parseInt(id) }, data: { name, class: classType } }); return json({ success: "Dredger location updated successfully!" }); } catch (error) { return json({ errors: { form: "Dredger location name already exists" } }, { status: 400 }); } } if (intent === "delete") { if (typeof id !== "string") { return json({ errors: { form: "Invalid dredger location ID" } }, { status: 400 }); } try { await prisma.dredgerLocation.delete({ where: { id: parseInt(id) } }); return json({ success: "Dredger location deleted successfully!" }); } catch (error) { return json({ errors: { form: "Cannot delete dredger location with existing reports" } }, { status: 400 }); } } return json({ errors: { form: "Invalid action" } }, { status: 400 }); }; export default function DredgerLocations() { const { user, dredgerLocations } = useLoaderData(); const actionData = useActionData(); const navigation = useNavigation(); const [editingLocation, setEditingLocation] = useState<{ id: number; name: string; class: string } | null>(null); const [showModal, setShowModal] = useState(false); const [toast, setToast] = useState<{ message: string; type: "success" | "error" } | null>(null); const isSubmitting = navigation.state === "submitting"; const isEditing = editingLocation !== null; // Handle success/error messages useEffect(() => { if (actionData?.success) { setToast({ message: actionData.success, type: "success" }); setShowModal(false); setEditingLocation(null); } else if (actionData?.errors?.form) { setToast({ message: actionData.errors.form, type: "error" }); } }, [actionData]); const handleEdit = (location: { id: number; name: string; class: string }) => { setEditingLocation(location); setShowModal(true); }; const handleAdd = () => { setEditingLocation(null); setShowModal(true); }; const handleCloseModal = () => { setShowModal(false); setEditingLocation(null); }; const getClassBadge = (classType: string) => { const colors = { C: "bg-blue-100 text-blue-800", D: "bg-green-100 text-green-800", SD: "bg-red-100 text-red-800", SP: "bg-purple-100 text-purple-800", PC: "bg-yellow-100 text-yellow-800", SOPA: "bg-indigo-100 text-indigo-800" }; return colors[classType as keyof typeof colors] || "bg-gray-100 text-gray-800"; }; const getClassIcon = (classType: string) => { switch (classType) { case "C": // return ( // // // // ); // case "D": // return ( // // // // ); // case "SP": // return ( // // // // ); // case "SD": // return ( // // // // ); // case "PC": // return ( // // // // ); // case "SOPA": // return ( // // // // ); default: return ( ); } }; return (

Dredger Locations Management

Manage dredger locations with different classes

{/* Locations Table */}
{dredgerLocations.map((location) => ( ))}
Location Class Reports Count Actions
{getClassIcon(location.class)}
{location.name}
{/*
ID #{location.id}
*/}
{location.class.toUpperCase()} - {location.class === 's' ? 'Standard' : location.class === 'd' ? 'Deep' : 'Special'} {location._count.reports} reports
{dredgerLocations.length === 0 && (

No dredger locations

Get started by creating your first dredger location.

)}
{/* Form Modal */} {/* Toast Notifications */} {toast && ( setToast(null)} /> )}
); }