220 lines
8.4 KiB
TypeScript
220 lines
8.4 KiB
TypeScript
import React, { useState } from "react";
|
||
import {
|
||
DocumentText,
|
||
DocumentDownload,
|
||
Refresh,
|
||
Activity,
|
||
InfoCircle
|
||
} from "iconsax-react";
|
||
import Button from "../../components/Button";
|
||
import Pagination from "../../components/Pagination";
|
||
import TitleLine from "../../components/TitleLine";
|
||
import PageLoading from "../../components/PageLoading";
|
||
// import Error from "../../components/Error"; // Using custom error display
|
||
import FilterPanel from "./components/FilterPanel";
|
||
import AccessLogsTable from "./components/AccessLogsTable";
|
||
import LogDetailsModal from "./components/LogDetailsModal";
|
||
import { useAccessLogs, useAccessLogDetail } from "./hooks/useAccessLogs";
|
||
import { AccessLog } from "./types/AccessLogTypes";
|
||
|
||
const AccessLogsList: React.FC = () => {
|
||
const {
|
||
logs,
|
||
loading,
|
||
error,
|
||
total,
|
||
filters,
|
||
updateFilters,
|
||
resetFilters,
|
||
exportLogs,
|
||
refetch,
|
||
} = useAccessLogs();
|
||
|
||
const { log: selectedLog, fetchLog, clearLog } = useAccessLogDetail();
|
||
const [isDetailsModalOpen, setIsDetailsModalOpen] = useState(false);
|
||
|
||
const handleViewDetails = async (log: AccessLog) => {
|
||
await fetchLog(log.id);
|
||
setIsDetailsModalOpen(true);
|
||
};
|
||
|
||
const handleCloseDetailsModal = () => {
|
||
setIsDetailsModalOpen(false);
|
||
clearLog();
|
||
};
|
||
|
||
const handleSort = (field: string, order: "ASC" | "DESC") => {
|
||
updateFilters({ sortBy: field, sortOrder: order });
|
||
};
|
||
|
||
const handlePageChange = (page: number) => {
|
||
updateFilters({ page });
|
||
};
|
||
|
||
const handleExport = async () => {
|
||
try {
|
||
await exportLogs();
|
||
} catch (error) {
|
||
console.error("خطا در خروجی گرفتن:", error);
|
||
}
|
||
};
|
||
|
||
if (error) {
|
||
return (
|
||
<div className="p-6">
|
||
<TitleLine title="لاگهای دسترسی" />
|
||
<div className="bg-red-50 border border-red-200 rounded-lg p-4">
|
||
<div className="flex items-center justify-between">
|
||
<p className="text-red-800">{error}</p>
|
||
<Button
|
||
onClick={refetch}
|
||
className="bg-red-600 text-white hover:bg-red-700"
|
||
>
|
||
تلاش مجدد
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div className="p-6 space-y-6">
|
||
{/* Header */}
|
||
<div className="flex items-center justify-between">
|
||
<div>
|
||
<TitleLine title="لاگهای دسترسی" />
|
||
<p className="text-gray-600 mt-2">
|
||
مشاهده و مدیریت تمام فعالیتهای سیستم
|
||
</p>
|
||
</div>
|
||
|
||
<div className="flex items-center gap-3">
|
||
<Button
|
||
onClick={refetch}
|
||
disabled={loading}
|
||
className="flex items-center gap-2 border border-gray-300 bg-white text-gray-700 hover:bg-gray-50"
|
||
>
|
||
<Refresh size={16} className={loading ? "animate-spin" : ""} />
|
||
بروزرسانی
|
||
</Button>
|
||
|
||
<Button
|
||
onClick={handleExport}
|
||
disabled={loading || !logs || logs.length === 0}
|
||
className="flex items-center gap-2 border border-gray-300 bg-white text-gray-700 hover:bg-gray-50"
|
||
>
|
||
<DocumentDownload size={16} />
|
||
خروجی CSV
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Stats Summary */}
|
||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4">
|
||
<div className="flex items-center gap-3">
|
||
<div className="flex-shrink-0 p-2 bg-blue-100 rounded-lg">
|
||
<DocumentText size={20} className="text-blue-600" />
|
||
</div>
|
||
<div>
|
||
<p className="text-sm font-medium text-gray-600">کل لاگها</p>
|
||
<p className="text-xl font-bold text-gray-900">
|
||
{(total || 0).toLocaleString('fa-IR')}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4">
|
||
<div className="flex items-center gap-3">
|
||
<div className="flex-shrink-0 p-2 bg-green-100 rounded-lg">
|
||
<Activity size={20} className="text-green-600" />
|
||
</div>
|
||
<div>
|
||
<p className="text-sm font-medium text-gray-600">صفحه فعلی</p>
|
||
<p className="text-xl font-bold text-gray-900">
|
||
{filters.page || 1}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4">
|
||
<div className="flex items-center gap-3">
|
||
<div className="flex-shrink-0 p-2 bg-purple-100 rounded-lg">
|
||
<InfoCircle size={20} className="text-purple-600" />
|
||
</div>
|
||
<div>
|
||
<p className="text-sm font-medium text-gray-600">نمایش در صفحه</p>
|
||
<p className="text-xl font-bold text-gray-900">
|
||
{filters.limit || 20}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Filter Panel */}
|
||
<FilterPanel
|
||
filters={filters}
|
||
onFiltersChange={updateFilters}
|
||
onReset={resetFilters}
|
||
loading={loading}
|
||
/>
|
||
|
||
{/* Loading State */}
|
||
{loading && <PageLoading />}
|
||
|
||
{/* Table */}
|
||
{!loading && (
|
||
<>
|
||
<AccessLogsTable
|
||
logs={logs}
|
||
loading={loading}
|
||
onViewDetails={handleViewDetails}
|
||
onSort={handleSort}
|
||
sortBy={filters.sortBy}
|
||
sortOrder={filters.sortOrder}
|
||
/>
|
||
|
||
{/* Pagination */}
|
||
{total > (filters.limit || 20) && (
|
||
<div className="flex justify-center">
|
||
<Pagination
|
||
currentPage={filters.page || 1}
|
||
totalPages={Math.ceil(total / (filters.limit || 20))}
|
||
onPageChange={handlePageChange}
|
||
/>
|
||
</div>
|
||
)}
|
||
</>
|
||
)}
|
||
|
||
{/* Details Modal */}
|
||
<LogDetailsModal
|
||
log={selectedLog}
|
||
isOpen={isDetailsModalOpen}
|
||
onClose={handleCloseDetailsModal}
|
||
/>
|
||
|
||
{/* Empty State Info */}
|
||
{!loading && (!logs || logs.length === 0) && !error && (
|
||
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4">
|
||
<div className="flex items-center gap-3">
|
||
<InfoCircle size={20} className="text-blue-600" />
|
||
<div>
|
||
<h3 className="text-sm font-medium text-blue-900">راهنما</h3>
|
||
<p className="text-sm text-blue-700 mt-1">
|
||
از فیلترهای بالا برای جستجوی دقیقتر استفاده کنید. میتوانید بر اساس نوع عملیات، کاربر، تاریخ و سایر معیارها جستجو کنید.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default AccessLogsList;
|