This commit is contained in:
2026-01-23 20:35:40 +03:00
parent cf3b0e48ec
commit 66c151653e
137 changed files with 41495 additions and 0 deletions

View File

@@ -0,0 +1,212 @@
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>
);
}