import type { LoaderFunctionArgs, ActionFunctionArgs } from "@remix-run/node"; import { json } from "@remix-run/node"; import { useLoaderData, useActionData, useNavigation, useSearchParams } from "@remix-run/react"; import { useState, useEffect } from "react"; import { requireUser } from "~/lib/auth.server"; import { useDebounce } from "~/hooks/useDebounce"; import { getCustomers, createCustomer, updateCustomer, deleteCustomer, getCustomerById } from "~/lib/customer-management.server"; import { validateCustomer } from "~/lib/validation"; import { DashboardLayout } from "~/components/layout/DashboardLayout"; import { CustomerList } from "~/components/customers/CustomerList"; import { CustomerForm } from "~/components/customers/CustomerForm"; import { CustomerDetailsView } from "~/components/customers/CustomerDetailsView"; import { Modal } from "~/components/ui/Modal"; import { Button } from "~/components/ui/Button"; import { Input } from "~/components/ui/Input"; import { Flex } from "~/components/layout/Flex"; import type { CustomerWithVehicles } from "~/types/database"; export async function loader({ request }: LoaderFunctionArgs) { const user = await requireUser(request); const url = new URL(request.url); const searchQuery = url.searchParams.get("search") || ""; const page = parseInt(url.searchParams.get("page") || "1"); const limit = parseInt(url.searchParams.get("limit") || "10"); const { customers, total, totalPages } = await getCustomers(searchQuery, page, limit); return json({ customers, total, totalPages, currentPage: page, searchQuery, user, }); } export async function action({ request }: ActionFunctionArgs) { const user = await requireUser(request); const formData = await request.formData(); const action = formData.get("_action") as string; switch (action) { case "create": { const customerData = { name: formData.get("name") as string, phone: formData.get("phone") as string || undefined, email: formData.get("email") as string || undefined, address: formData.get("address") as string || undefined, }; // Validate customer data const validation = validateCustomer(customerData); if (!validation.isValid) { return json({ success: false, errors: validation.errors, action: "create" }, { status: 400 }); } const result = await createCustomer(customerData); if (result.success) { return json({ success: true, customer: result.customer, action: "create", message: "تم إنشاء العميل بنجاح" }); } else { return json({ success: false, error: result.error, action: "create" }, { status: 400 }); } } case "update": { const id = parseInt(formData.get("id") as string); const customerData = { name: formData.get("name") as string, phone: formData.get("phone") as string || undefined, email: formData.get("email") as string || undefined, address: formData.get("address") as string || undefined, }; // Validate customer data const validation = validateCustomer(customerData); if (!validation.isValid) { return json({ success: false, errors: validation.errors, action: "update" }, { status: 400 }); } const result = await updateCustomer(id, customerData); if (result.success) { return json({ success: true, customer: result.customer, action: "update", message: "تم تحديث العميل بنجاح" }); } else { return json({ success: false, error: result.error, action: "update" }, { status: 400 }); } } case "delete": { const id = parseInt(formData.get("id") as string); const result = await deleteCustomer(id); if (result.success) { return json({ success: true, action: "delete", message: "تم حذف العميل بنجاح" }); } else { return json({ success: false, error: result.error, action: "delete" }, { status: 400 }); } } case "get": { const id = parseInt(formData.get("id") as string); const customer = await getCustomerById(id); if (customer) { return json({ success: true, customer, action: "get" }); } else { return json({ success: false, error: "العميل غير موجود", action: "get" }, { status: 404 }); } } default: return json({ success: false, error: "إجراء غير صحيح", action: "unknown" }, { status: 400 }); } } export default function CustomersPage() { const { customers, total, totalPages, currentPage, searchQuery, user } = useLoaderData(); const actionData = useActionData(); const navigation = useNavigation(); const [searchParams, setSearchParams] = useSearchParams(); const [showCreateModal, setShowCreateModal] = useState(false); const [showEditModal, setShowEditModal] = useState(false); const [showViewModal, setShowViewModal] = useState(false); const [selectedCustomer, setSelectedCustomer] = useState(null); const [searchValue, setSearchValue] = useState(searchQuery); const isLoading = navigation.state !== "idle"; // Debounce search value to avoid too many requests const debouncedSearchValue = useDebounce(searchValue, 300); // Handle search automatically when debounced value changes useEffect(() => { if (debouncedSearchValue !== searchQuery) { const newSearchParams = new URLSearchParams(searchParams); if (debouncedSearchValue) { newSearchParams.set("search", debouncedSearchValue); } else { newSearchParams.delete("search"); } newSearchParams.set("page", "1"); // Reset to first page setSearchParams(newSearchParams); } }, [debouncedSearchValue, searchQuery, searchParams, setSearchParams]); // Clear search function const clearSearch = () => { setSearchValue(""); }; // Handle pagination const handlePageChange = (page: number) => { const newSearchParams = new URLSearchParams(searchParams); newSearchParams.set("page", page.toString()); setSearchParams(newSearchParams); }; // Handle create customer const handleCreateCustomer = () => { setSelectedCustomer(null); setShowCreateModal(true); }; // Handle view customer const handleViewCustomer = (customer: CustomerWithVehicles) => { setSelectedCustomer(customer); setShowViewModal(true); }; // Handle edit customer const handleEditCustomer = (customer: CustomerWithVehicles) => { setSelectedCustomer(customer); setShowEditModal(true); }; // Close modals on successful action useEffect(() => { if (actionData?.success && actionData.action === "create") { setShowCreateModal(false); } if (actionData?.success && actionData.action === "update") { setShowEditModal(false); } }, [actionData]); return (
{/* Header */}

إدارة العملاء

إجمالي العملاء: {total}

{/* Search */}
setSearchValue(e.target.value)} startIcon={ } endIcon={ searchValue && (
) } />
{(searchQuery || debouncedSearchValue !== searchQuery) && (
{debouncedSearchValue !== searchQuery && ( جاري البحث... )}
)}
{/* Action Messages */} {actionData?.success && actionData.message && (
{actionData.message}
)} {actionData?.error && (
{actionData.error}
)} {/* Customer List */} {/* Create Customer Modal */} setShowCreateModal(false)} title="إضافة عميل جديد" > setShowCreateModal(false)} errors={actionData?.action === "create" ? actionData.errors : undefined} isLoading={isLoading} /> {/* View Customer Modal */} setShowViewModal(false)} title={selectedCustomer ? `تفاصيل العميل - ${selectedCustomer.name}` : "تفاصيل العميل"} size="xl" > {selectedCustomer && ( { setShowViewModal(false); handleEditCustomer(selectedCustomer); }} onClose={() => setShowViewModal(false)} /> )} {/* Edit Customer Modal */} setShowEditModal(false)} title="تعديل العميل" > {selectedCustomer && ( setShowEditModal(false)} errors={actionData?.action === "update" ? actionData.errors : undefined} isLoading={isLoading} /> )}
); }