Files
AthenaFE/components/features/logs/LogsPage.tsx
T
2025-11-02 10:08:56 +01:00

137 lines
4.0 KiB
TypeScript

import {
useDeferredValue,
useEffect,
useMemo,
useState,
useCallback,
} from "react";
import { View, Text } from "react-native";
import { useFocusEffect } from "@react-navigation/native";
import { LogsTable } from "@/components/features/logs/LogsTable";
import { LoadingSpinner } from "@/components/ui/LoadingSpinner";
import { NoData } from "@/components/ui/NoData";
import { useGetUserLogsQuery } from "@/store/api/usersApi";
import { TableSortDirection } from "@/constants/tableSortDirectionEnum";
import { useAppSelector } from "@/store/hooks";
import { selectIsMobile } from "@/store/screen/screenSizeSlice";
export const LogsPage = () => {
const [page, setPage] = useState(0);
const [itemsPerPage, setItemsPerPage] = useState(25);
const [searchQuery, setSearchQuery] = useState("");
const [sortColumn, setSortColumn] = useState<string | null>(null);
const [sortDirection, setSortDirection] = useState<TableSortDirection>(
TableSortDirection.ASCENDING
);
const isMobile = useAppSelector(selectIsMobile);
const deferredSearch = useDeferredValue(searchQuery);
const [debouncedSearch, setDebouncedSearch] = useState(deferredSearch);
useEffect(() => {
const handler = setTimeout(
() => setDebouncedSearch(deferredSearch.trim()),
450
);
return () => clearTimeout(handler);
}, [deferredSearch]);
const queryArgs = useMemo(() => {
const searchParam =
debouncedSearch && debouncedSearch.length >= 2
? debouncedSearch
: undefined;
return {
page: page + 1,
limit: itemsPerPage,
search: searchParam,
} as const;
}, [page, itemsPerPage, debouncedSearch]);
const {
data: logsData,
isLoading,
isFetching,
error,
refetch,
} = useGetUserLogsQuery(queryArgs);
const logs = logsData?.items ?? [];
const totalItems = logsData?.total ?? 0;
const from = logs.length ? page * itemsPerPage + 1 : 0;
const to = logs.length ? Math.min(from + logs.length - 1, totalItems) : 0;
// Refetch whenever the screen/page gains focus
useFocusEffect(
useCallback(() => {
refetch();
}, [refetch])
);
return (
<View
className={`flex-1 p-1 ${isMobile ? "p-1" : "p-5"} bg-primaryPurpleLight`}
>
<Text
className={`text-2xl font-bold ${
isMobile ? "mb-1" : "mb-4"
} text-white`}
>
Users login activity
</Text>
<View
className={`bg-lightGray rounded-lg ${isMobile ? "p-1" : "p-5"} flex-1`}
>
{isLoading ? (
<View className="flex-1 justify-center items-center py-10">
<LoadingSpinner />
<Text className="mt-2">Loading logs...</Text>
</View>
) : error ? (
<View className="flex-1 justify-center items-center py-10">
<NoData
message="Error loading logs"
onRetry={refetch}
isRetrying={isFetching}
/>
</View>
) : (
<LogsTable
logs={logs}
page={page}
itemsPerPage={itemsPerPage}
totalItems={totalItems}
from={from}
to={to}
searchQuery={searchQuery}
onSearch={(q) => {
setSearchQuery(q);
setPage(0);
}}
sortColumn={sortColumn}
sortDirection={sortDirection}
onSort={(column) => {
if (sortColumn === column) {
setSortDirection((d) =>
d === TableSortDirection.ASCENDING
? TableSortDirection.DESCENDING
: TableSortDirection.ASCENDING
);
} else {
setSortColumn(column);
setSortDirection(TableSortDirection.ASCENDING);
}
setPage(0);
}}
onItemsPerPageChange={(value) => {
setItemsPerPage(value);
setPage(0);
}}
onPageChange={(newPage) => setPage(newPage)}
/>
)}
</View>
</View>
);
};