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

233 lines
6.8 KiB
TypeScript

import { useState, memo } from 'react';
import { Form } from '@remix-run/react';
import { DataTable, Pagination, Button, Text, ConfirmModal } from '~/components/ui';
import { getAuthLevelName, getStatusName } from '~/lib/user-utils';
import { useSettings } from '~/contexts/SettingsContext';
import { AUTH_LEVELS } from '~/types/auth';
import type { UserWithoutPassword } from '~/types/database';
interface UserListProps {
users: UserWithoutPassword[];
currentPage: number;
totalPages: number;
onPageChange: (page: number) => void;
onEdit: (user: UserWithoutPassword) => void;
onDelete: (userId: number) => void;
onToggleStatus: (userId: number) => void;
currentUserAuthLevel: number;
loading?: boolean;
}
export const UserList = memo(function UserList({
users,
currentPage,
totalPages,
onPageChange,
onEdit,
onDelete,
onToggleStatus,
currentUserAuthLevel,
loading = false,
}: UserListProps) {
const { formatDate } = useSettings();
const [deleteModal, setDeleteModal] = useState<{
isOpen: boolean;
user: UserWithoutPassword | null;
}>({ isOpen: false, user: null });
const [statusModal, setStatusModal] = useState<{
isOpen: boolean;
user: UserWithoutPassword | null;
}>({ isOpen: false, user: null });
const handleDeleteClick = (user: UserWithoutPassword) => {
setDeleteModal({ isOpen: true, user });
};
const handleStatusClick = (user: UserWithoutPassword) => {
setStatusModal({ isOpen: true, user });
};
const handleDeleteConfirm = () => {
if (deleteModal.user) {
onDelete(deleteModal.user.id);
}
setDeleteModal({ isOpen: false, user: null });
};
const handleStatusConfirm = () => {
if (statusModal.user) {
onToggleStatus(statusModal.user.id);
}
setStatusModal({ isOpen: false, user: null });
};
const canEditUser = (user: UserWithoutPassword) => {
// Superadmin can edit anyone
if (currentUserAuthLevel === AUTH_LEVELS.SUPERADMIN) return true;
// Admin cannot edit superadmin
if (currentUserAuthLevel === AUTH_LEVELS.ADMIN && user.authLevel === AUTH_LEVELS.SUPERADMIN) {
return false;
}
return true;
};
const canDeleteUser = (user: UserWithoutPassword) => {
// Same rules as edit
return canEditUser(user);
};
const columns = [
{
key: 'name',
header: 'الاسم',
sortable: true,
render: (user: UserWithoutPassword) => (
<div>
<Text weight="medium">{user.name}</Text>
<Text size="sm" color="secondary">@{user.username}</Text>
</div>
),
},
{
key: 'email',
header: 'البريد الإلكتروني',
sortable: true,
},
{
key: 'authLevel',
header: 'مستوى الصلاحية',
render: (user: UserWithoutPassword) => {
const levelName = getAuthLevelName(user.authLevel);
const colorClass = user.authLevel === AUTH_LEVELS.SUPERADMIN
? 'text-purple-600 bg-purple-100'
: user.authLevel === AUTH_LEVELS.ADMIN
? 'text-blue-600 bg-blue-100'
: 'text-gray-600 bg-gray-100';
return (
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${colorClass}`}>
{levelName}
</span>
);
},
},
{
key: 'status',
header: 'الحالة',
render: (user: UserWithoutPassword) => {
const statusName = getStatusName(user.status);
const colorClass = user.status === 'active'
? 'text-green-600 bg-green-100'
: 'text-red-600 bg-red-100';
return (
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${colorClass}`}>
{statusName}
</span>
);
},
},
{
key: 'createdDate',
header: 'تاريخ الإنشاء',
sortable: true,
render: (user: UserWithoutPassword) => (
<Text size="sm" color="secondary">
{formatDate(user.createdDate)}
</Text>
),
},
{
key: 'actions',
header: 'الإجراءات',
render: (user: UserWithoutPassword) => (
<div className="flex items-center space-x-2 space-x-reverse">
{canEditUser(user) && (
<Button
size="sm"
variant="outline"
onClick={() => onEdit(user)}
className='w-24'
>
تعديل
</Button>
)}
{canEditUser(user) && (
<Button
size="sm"
variant="outline"
onClick={() => handleStatusClick(user)}
className='w-24'
>
{user.status === 'active' ? 'إلغاء تفعيل' : 'تفعيل'}
</Button>
)}
{canDeleteUser(user) && (
<Button
size="sm"
variant="danger"
onClick={() => handleDeleteClick(user)}
className='w-24'
>
حذف
</Button>
)}
</div>
),
},
];
return (
<>
<DataTable
data={users}
columns={columns}
loading={loading}
emptyMessage="لا توجد مستخدمين"
/>
{totalPages > 1 && (
<div className="mt-6">
<Pagination
currentPage={currentPage}
totalPages={totalPages}
onPageChange={onPageChange}
/>
</div>
)}
{/* Delete Confirmation Modal */}
<ConfirmModal
isOpen={deleteModal.isOpen}
onClose={() => setDeleteModal({ isOpen: false, user: null })}
onConfirm={handleDeleteConfirm}
title="تأكيد الحذف"
message={`هل أنت متأكد من حذف المستخدم "${deleteModal.user?.name}"؟ هذا الإجراء لا يمكن التراجع عنه.`}
confirmText="حذف"
cancelText="إلغاء"
variant="danger"
/>
{/* Status Toggle Confirmation Modal */}
<ConfirmModal
isOpen={statusModal.isOpen}
onClose={() => setStatusModal({ isOpen: false, user: null })}
onConfirm={handleStatusConfirm}
title={statusModal.user?.status === 'active' ? 'إلغاء تفعيل المستخدم' : 'تفعيل المستخدم'}
message={
statusModal.user?.status === 'active'
? `هل أنت متأكد من إلغاء تفعيل المستخدم "${statusModal.user?.name}`
: `هل أنت متأكد من تفعيل المستخدم "${statusModal.user?.name}`
}
confirmText={statusModal.user?.status === 'active' ? 'إلغاء تفعيل' : 'تفعيل'}
cancelText="إلغاء"
variant={statusModal.user?.status === 'active' ? 'warning' : 'info'}
/>
</>
);
});