car_mms/app/components/tables/EnhancedCustomerTable.tsx
2025-09-11 14:22:27 +03:00

212 lines
6.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState, useMemo } from 'react';
import { DataTable } from '~/components/ui/DataTable';
import { Button } from '~/components/ui/Button';
import { Text } from '~/components/ui/Text';
import { processTableData, type TableState } from '~/lib/table-utils';
import { useSettings } from '~/contexts/SettingsContext';
import type { Customer } from '~/types/database';
interface EnhancedCustomerTableProps {
customers: Customer[];
loading?: boolean;
onEdit?: (customer: Customer) => void;
onDelete?: (customer: Customer) => void;
onView?: (customer: Customer) => void;
}
export function EnhancedCustomerTable({
customers,
loading = false,
onEdit,
onDelete,
onView,
}: EnhancedCustomerTableProps) {
const { formatDate } = useSettings();
const [tableState, setTableState] = useState<TableState>({
search: '',
filters: {},
sort: { key: 'name', direction: 'asc' },
pagination: { page: 1, pageSize: 10 },
});
// Define searchable fields
const searchableFields = ['name', 'phone', 'email', 'address'] as const;
// Process table data
const processedData = useMemo(() => {
return processTableData(customers, tableState, searchableFields);
}, [customers, tableState]);
// Handle sorting
const handleSort = (key: string, direction: 'asc' | 'desc') => {
setTableState(prev => ({
...prev,
sort: { key, direction },
}));
};
// Handle page change
const handlePageChange = (page: number) => {
setTableState(prev => ({
...prev,
pagination: { ...prev.pagination, page },
}));
};
// Define table columns
const columns = [
{
key: 'name' as keyof Customer,
header: 'اسم العميل',
sortable: true,
filterable: true,
render: (customer: Customer) => (
<div>
<Text weight="medium">{customer.name}</Text>
</div>
),
},
{
key: 'phone' as keyof Customer,
header: 'رقم الهاتف',
sortable: true,
filterable: true,
render: (customer: Customer) => (
<Text dir="ltr" className="text-left">
{customer.phone || '-'}
</Text>
),
},
{
key: 'email' as keyof Customer,
header: 'البريد الإلكتروني',
sortable: true,
filterable: true,
render: (customer: Customer) => (
<Text dir="ltr" className="text-left">
{customer.email || '-'}
</Text>
),
},
{
key: 'address' as keyof Customer,
header: 'العنوان',
filterable: true,
render: (customer: Customer) => (
<Text className="max-w-xs truncate" title={customer.address || undefined}>
{customer.address || '-'}
</Text>
),
},
{
key: 'createdDate' as keyof Customer,
header: 'تاريخ الإنشاء',
sortable: true,
render: (customer: Customer) => (
<Text size="sm" color="secondary">
{formatDate(customer.createdDate)}
</Text>
),
},
];
return (
<div className="space-y-4">
{/* Table Header */}
<div className="flex justify-between items-center">
<div>
<Text size="lg" weight="semibold">
قائمة العملاء
</Text>
<Text size="sm" color="secondary">
إدارة بيانات العملاء
</Text>
</div>
<div className="flex items-center space-x-2 space-x-reverse">
<Text size="sm" color="secondary">
المجموع: {processedData.originalCount}
</Text>
{processedData.filteredCount !== processedData.originalCount && (
<Text size="sm" color="secondary">
(مفلتر: {processedData.filteredCount})
</Text>
)}
</div>
</div>
{/* Enhanced Data Table */}
<DataTable
data={processedData.data}
columns={columns}
loading={loading}
emptyMessage="لا يوجد عملاء مسجلين"
searchable
searchPlaceholder="البحث في العملاء..."
filterable
onSort={handleSort}
sortKey={tableState.sort?.key}
sortDirection={tableState.sort?.direction}
pagination={{
enabled: true,
currentPage: tableState.pagination.page,
pageSize: tableState.pagination.pageSize,
totalItems: processedData.filteredCount,
onPageChange: handlePageChange,
}}
actions={{
label: 'الإجراءات',
render: (customer: Customer) => (
<div className="flex items-center space-x-2 space-x-reverse">
{onView && (
<Button
size="sm"
variant="ghost"
onClick={() => onView(customer)}
icon={
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
</svg>
}
>
عرض
</Button>
)}
{onEdit && (
<Button
size="sm"
variant="ghost"
onClick={() => onEdit(customer)}
icon={
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
</svg>
}
>
تعديل
</Button>
)}
{onDelete && (
<Button
size="sm"
variant="ghost"
onClick={() => onDelete(customer)}
icon={
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg>
}
>
حذف
</Button>
)}
</div>
),
}}
/>
</div>
);
}