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: "Equipment Management - Phosphat Report" }]; export const loader = async ({ request }: LoaderFunctionArgs) => { const user = await requireAuthLevel(request, 2); const equipment = await prisma.equipment.findMany({ orderBy: [{ category: 'asc' }, { model: 'asc' }] }); return json({ user, equipment }); }; 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 category = formData.get("category"); const model = formData.get("model"); const number = formData.get("number"); if (intent === "create") { if (typeof category !== "string" || category.length === 0) { return json({ errors: { category: "Category is required" } }, { status: 400 }); } if (typeof model !== "string" || model.length === 0) { return json({ errors: { model: "Model is required" } }, { status: 400 }); } if (typeof number !== "string" || isNaN(parseInt(number)) || parseInt(number) < 1) { return json({ errors: { number: "Valid number is required" } }, { status: 400 }); } try { await prisma.equipment.create({ data: { category, model, number: parseInt(number) } }); return json({ success: "Equipment created successfully!" }); } catch (error) { return json({ errors: { form: "Failed to create equipment" } }, { status: 400 }); } } if (intent === "update") { if (typeof category !== "string" || category.length === 0) { return json({ errors: { category: "Category is required" } }, { status: 400 }); } if (typeof model !== "string" || model.length === 0) { return json({ errors: { model: "Model is required" } }, { status: 400 }); } if (typeof number !== "string" || isNaN(parseInt(number)) || parseInt(number) < 1) { return json({ errors: { number: "Valid number is required" } }, { status: 400 }); } if (typeof id !== "string") { return json({ errors: { form: "Invalid equipment ID" } }, { status: 400 }); } try { await prisma.equipment.update({ where: { id: parseInt(id) }, data: { category, model, number: parseInt(number) } }); return json({ success: "Equipment updated successfully!" }); } catch (error) { return json({ errors: { form: "Failed to update equipment" } }, { status: 400 }); } } if (intent === "delete") { if (typeof id !== "string") { return json({ errors: { form: "Invalid equipment ID" } }, { status: 400 }); } try { await prisma.equipment.delete({ where: { id: parseInt(id) } }); return json({ success: "Equipment deleted successfully!" }); } catch (error) { return json({ errors: { form: "Failed to delete equipment" } }, { status: 400 }); } } return json({ errors: { form: "Invalid action" } }, { status: 400 }); }; export default function Equipment() { const { user, equipment } = useLoaderData(); const actionData = useActionData(); const navigation = useNavigation(); const [editingEquipment, setEditingEquipment] = useState<{ id: number; category: string; model: string; number: number } | 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 = editingEquipment !== null; // Handle success/error messages useEffect(() => { if (actionData?.success) { setToast({ message: actionData.success, type: "success" }); setShowModal(false); setEditingEquipment(null); } else if (actionData?.errors?.form) { setToast({ message: actionData.errors.form, type: "error" }); } }, [actionData]); const handleEdit = (item: { id: number; category: string; model: string; number: number }) => { setEditingEquipment(item); setShowModal(true); }; const handleAdd = () => { setEditingEquipment(null); setShowModal(true); }; const handleCloseModal = () => { setShowModal(false); setEditingEquipment(null); }; const getCategoryBadge = (category: string) => { const colors = { Dozer: "bg-yellow-100 text-yellow-800", Excavator: "bg-blue-100 text-blue-800", Loader: "bg-green-100 text-green-800", Truck: "bg-red-100 text-red-800" }; return colors[category as keyof typeof colors] || "bg-gray-100 text-gray-800"; }; const getCategoryIcon = (category: string) => { // Using the same heavy equipment SVG icon with different colors based on category const color = { "Dozer": "#f59e0b", // yellow-500 "Excavator": "#3b82f6", // blue-500 "Loader": "#10b981", // green-500 "Truck": "#ef4444", // red-500 }[category] || "#6b7280"; // gray-500 default return ( ); }; return (

Equipment Management

Manage your fleet equipment and machinery

{/* Equipment Table */}
{equipment.map((item) => ( ))}
Equipment Category Number Actions
{getCategoryIcon(item.category)}
{item.model}
{/*
ID #{item.id}
*/}
{item.category} {item.number}
{equipment.length === 0 && (

No equipment

Get started by adding your first equipment.

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