access logs + audio
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user