import { useState, useMemo, memo } from "react";
import {
Text,
TextInput,
Stack,
Group,
Box,
Container,
Divider,
UnstyledButton,
Select,
Pagination,
Code,
Alert,
} from "@mantine/core";
import {
MagnifyingGlassIcon,
CaretUpIcon,
CaretDownIcon,
CheckIcon,
XIcon,
ChecksIcon,
} from "@phosphor-icons/react";
import { Activity, ActivitySearchParams } from "../types";
import { useActivities } from "../queries";
import Sheet from "@/components/sheet/sheet";
import { useSheet } from "@/hooks/use-sheet";
interface ActivityListItemProps {
activity: Activity;
onClick: () => void;
}
const ActivityListItem = memo(({ activity, onClick }: ActivityListItemProps) => {
const playerName = typeof activity.player === "object" && activity.player
? `${activity.player.first_name} ${activity.player.last_name}`
: "System";
const formatDate = (dateStr: string) => {
const date = new Date(dateStr);
return date.toLocaleString();
};
return (
{activity.name}
{activity.success ? (
) : (
)}
{playerName}
{activity.duration}ms
{formatDate(activity.created)}
{activity.error && (
{activity.error}
)}
);
});
interface ActivityDetailsSheetProps {
activity: Activity | null;
isOpen: boolean;
onClose: () => void;
}
const ActivityDetailsSheet = memo(({ activity, isOpen, onClose }: ActivityDetailsSheetProps) => {
if (!activity) return null;
const playerName = typeof activity.player === "object" && activity.player
? `${activity.player.first_name} ${activity.player.last_name}`
: "System";
const formatDate = (dateStr: string) => {
const date = new Date(dateStr);
return date.toLocaleString();
};
return (
Function Name
{activity.name}
Status
{activity.success ? (
<>
Success
>
) : (
<>
Failed
>
)}
Player
{playerName}
Duration
{activity.duration}ms
Created
{formatDate(activity.created)}
{activity.user_agent && (
User Agent
{activity.user_agent}
)}
{activity.error && (
Error Message
{activity.error}
)}
{activity.arguments && (
Arguments
{JSON.stringify(activity.arguments, null, 2)}
)}
);
});
const ActivitiesResults = ({ searchParams, page, setPage, onActivityClick }: any) => {
const { data: result } = useActivities(searchParams);
return (
<>
{result.items.map((activity: Activity, index: number) => (
onActivityClick(activity)}
/>
{index < result.items.length - 1 && }
))}
{result.items.length === 0 && (
No activities found
)}
{result.totalPages > 1 && (
)}
>
);
};
export const ActivitiesTable = () => {
const [page, setPage] = useState(1);
const [search, setSearch] = useState("");
const [successFilter, setSuccessFilter] = useState(null);
const [sortBy, setSortBy] = useState("-created");
const [selectedActivity, setSelectedActivity] = useState(null);
const {
isOpen: detailsOpened,
open: openDetails,
close: closeDetails,
} = useSheet();
const searchParams: ActivitySearchParams = useMemo(
() => ({
page,
perPage: 100,
name: search || undefined,
success: successFilter === "success" ? true : successFilter === "failure" ? false : undefined,
sortBy,
}),
[page, search, successFilter, sortBy]
);
const { data: result } = useActivities(searchParams);
const handleSort = (field: string) => {
setSortBy((prev) => {
if (prev === field) return `-${field}`;
if (prev === `-${field}`) return field;
return `-${field}`;
});
};
const getSortIcon = (field: string) => {
if (sortBy === field) return ;
if (sortBy === `-${field}`) return ;
return null;
};
const handleActivityClick = (activity: Activity) => {
setSelectedActivity(activity);
openDetails();
};
const handleCloseDetails = () => {
setSelectedActivity(null);
closeDetails();
};
return (
{
setSearch(e.currentTarget.value);
setPage(1);
}}
leftSection={}
size="md"
/>
{result.totalItems} total activities
Sort:
handleSort("created")}
style={{ display: "flex", alignItems: "center", gap: 4 }}
>
Date
{getSortIcon("created")}
•
handleSort("duration")}
style={{ display: "flex", alignItems: "center", gap: 4 }}
>
Duration
{getSortIcon("duration")}
);
};