135 lines
3.8 KiB
TypeScript
135 lines
3.8 KiB
TypeScript
import { useMemo, useState } from "react";
|
|
import { View, Text, ScrollView, GestureResponderEvent } from "react-native";
|
|
|
|
import { LogsTableControls } from "@/components/features/logs/LogsTableControls";
|
|
import { TablePagination } from "@/components/shared/TablePagination";
|
|
import { UserLoginLog } from "@/store/api/usersApi";
|
|
import { useAppSelector } from "@/store/hooks";
|
|
import { selectIsMobile } from "@/store/screen/screenSizeSlice";
|
|
import { DesktopLogsTable } from "@/components/features/logs/DesktopLogsTable";
|
|
import { MobileLogsTable } from "@/components/features/logs/MobileLogsTable";
|
|
import { TableSortDirection } from "@/constants/tableSortDirectionEnum";
|
|
|
|
interface LogsTableProps {
|
|
logs: UserLoginLog[];
|
|
page: number;
|
|
itemsPerPage: number;
|
|
totalItems: number;
|
|
from: number;
|
|
to: number;
|
|
searchQuery: string;
|
|
onSearch: (q: string) => void;
|
|
onItemsPerPageChange: (value: number) => void;
|
|
onPageChange: (page: number) => void;
|
|
sortColumn: string | null;
|
|
sortDirection: TableSortDirection;
|
|
onSort: (column: string) => void;
|
|
}
|
|
|
|
export const LogsTable = ({
|
|
logs,
|
|
page,
|
|
itemsPerPage,
|
|
totalItems,
|
|
from,
|
|
to,
|
|
searchQuery,
|
|
onSearch,
|
|
onItemsPerPageChange,
|
|
onPageChange,
|
|
sortColumn,
|
|
sortDirection,
|
|
onSort,
|
|
}: LogsTableProps) => {
|
|
const [menuVisible, setMenuVisible] = useState(false);
|
|
const [menuAnchor, setMenuAnchor] = useState<{ x: number; y: number }>({
|
|
x: 0,
|
|
y: 0,
|
|
});
|
|
const isMobile = useAppSelector(selectIsMobile);
|
|
|
|
const handleItemsPerPageButtonPress = (event: GestureResponderEvent) => {
|
|
const { pageX, pageY } = event.nativeEvent;
|
|
setMenuAnchor({ x: pageX, y: pageY });
|
|
setMenuVisible(true);
|
|
};
|
|
|
|
const sortedLogs = useMemo(() => {
|
|
if (!sortColumn) return logs;
|
|
const dir = sortDirection === TableSortDirection.DESCENDING ? -1 : 1;
|
|
const safe = (v?: string) => (v ?? "").toString().toLowerCase();
|
|
const out = [...logs];
|
|
out.sort((a, b) => {
|
|
let comp = 0;
|
|
switch (sortColumn) {
|
|
case "lastLoginAt": {
|
|
const at = new Date(a.lastLoginAt).getTime();
|
|
const bt = new Date(b.lastLoginAt).getTime();
|
|
comp = at - bt;
|
|
break;
|
|
}
|
|
case "name":
|
|
comp = safe(a.name).localeCompare(safe(b.name));
|
|
break;
|
|
case "email":
|
|
comp = safe(a.email).localeCompare(safe(b.email));
|
|
break;
|
|
case "activity":
|
|
comp = safe(a.activity).localeCompare(safe(b.activity));
|
|
break;
|
|
default:
|
|
comp = 0;
|
|
}
|
|
return comp * dir;
|
|
});
|
|
return out;
|
|
}, [logs, sortColumn, sortDirection]);
|
|
|
|
return (
|
|
<View className="flex-1">
|
|
<LogsTableControls
|
|
searchQuery={searchQuery}
|
|
menuVisible={menuVisible}
|
|
menuAnchor={menuAnchor}
|
|
onSearch={(q) => onSearch(q)}
|
|
onMenuDismiss={() => setMenuVisible(false)}
|
|
onItemsPerPageChange={onItemsPerPageChange}
|
|
itemsPerPage={itemsPerPage}
|
|
/>
|
|
|
|
{logs.length === 0 ? (
|
|
<View
|
|
className={`flex-1 items-center justify-center ${
|
|
isMobile ? "p-1" : "p-5"
|
|
}`}
|
|
>
|
|
<Text className="text-lg text-gray-500">
|
|
No logs match your search{searchQuery && ` for "${searchQuery}"`}
|
|
</Text>
|
|
</View>
|
|
) : isMobile ? (
|
|
<MobileLogsTable logs={sortedLogs} />
|
|
) : (
|
|
<ScrollView className="flex-1">
|
|
<DesktopLogsTable
|
|
sortColumn={sortColumn}
|
|
sortDirection={sortDirection}
|
|
onSort={onSort}
|
|
logs={sortedLogs}
|
|
/>
|
|
</ScrollView>
|
|
)}
|
|
|
|
<TablePagination
|
|
page={page}
|
|
itemsPerPage={itemsPerPage}
|
|
totalItems={totalItems}
|
|
from={from}
|
|
to={to}
|
|
onPageChange={onPageChange}
|
|
onItemsPerPageButtonPress={handleItemsPerPageButtonPress}
|
|
/>
|
|
</View>
|
|
);
|
|
};
|