122 lines
3.3 KiB
TypeScript
122 lines
3.3 KiB
TypeScript
import { memo } from "react";
|
|
import {
|
|
Text,
|
|
Stack,
|
|
Group,
|
|
Box,
|
|
Container,
|
|
Divider,
|
|
UnstyledButton,
|
|
} from "@mantine/core";
|
|
import { Trans, Plural, useLingui } from "@lingui/react/macro";
|
|
import { Player } from "../types";
|
|
import { usePlayersActivity } from "../queries";
|
|
|
|
interface PlayerActivityItemProps {
|
|
player: Player;
|
|
}
|
|
|
|
const PlayerActivityItem = memo(({ player }: PlayerActivityItemProps) => {
|
|
const { t, i18n } = useLingui();
|
|
|
|
const playerName = player.first_name && player.last_name
|
|
? `${player.first_name} ${player.last_name}`
|
|
: player.first_name || player.last_name || t`Unknown Player`;
|
|
|
|
const formatDate = (dateStr?: string) => {
|
|
if (!dateStr) return t`Never`;
|
|
const date = new Date(dateStr);
|
|
return date.toLocaleString(i18n.locale);
|
|
};
|
|
|
|
const getTimeSince = (dateStr?: string) => {
|
|
if (!dateStr) return t`Never active`;
|
|
const date = new Date(dateStr);
|
|
const now = new Date();
|
|
const diffMs = now.getTime() - date.getTime();
|
|
const diffMins = Math.floor(diffMs / 60000);
|
|
const diffHours = Math.floor(diffMins / 60);
|
|
const diffDays = Math.floor(diffHours / 24);
|
|
|
|
if (diffMins < 1) return t`Just now`;
|
|
if (diffMins < 60) return t`${diffMins}m ago`;
|
|
if (diffHours < 24) return t`${diffHours}h ago`;
|
|
if (diffDays < 30) return t`${diffDays}d ago`;
|
|
return formatDate(dateStr);
|
|
};
|
|
|
|
const isActive = player.last_activity &&
|
|
(new Date().getTime() - new Date(player.last_activity).getTime()) < 5 * 60 * 1000;
|
|
|
|
return (
|
|
<Box
|
|
w="100%"
|
|
p="md"
|
|
style={{
|
|
borderRadius: 0,
|
|
}}
|
|
>
|
|
<Group justify="space-between" align="flex-start" w="100%">
|
|
<Stack gap={4} flex={1}>
|
|
<Group gap="xs">
|
|
<Text size="sm" fw={600}>
|
|
{playerName}
|
|
</Text>
|
|
{isActive && (
|
|
<Box
|
|
w={8}
|
|
h={8}
|
|
style={{
|
|
borderRadius: "50%",
|
|
backgroundColor: "var(--mantine-color-green-6)",
|
|
}}
|
|
/>
|
|
)}
|
|
</Group>
|
|
<Group gap="md">
|
|
<Text size="xs" c="dimmed">
|
|
{getTimeSince(player.last_activity)}
|
|
</Text>
|
|
{player.last_activity && (
|
|
<Text size="xs" c="dimmed">
|
|
{formatDate(player.last_activity)}
|
|
</Text>
|
|
)}
|
|
</Group>
|
|
</Stack>
|
|
</Group>
|
|
</Box>
|
|
);
|
|
});
|
|
|
|
export const PlayersActivityTable = () => {
|
|
const { data: players } = usePlayersActivity();
|
|
|
|
return (
|
|
<Container size="100%" px={0}>
|
|
<Stack gap="xs">
|
|
<Group px="md" justify="space-between" align="center">
|
|
<Text size="10px" lh={0} c="dimmed">
|
|
<Plural value={players.length} one="# player" other="# players" />
|
|
</Text>
|
|
</Group>
|
|
|
|
<Stack gap={0}>
|
|
{players.map((player: Player, index: number) => (
|
|
<Box key={player.id}>
|
|
<PlayerActivityItem player={player} />
|
|
{index < players.length - 1 && <Divider />}
|
|
</Box>
|
|
))}
|
|
</Stack>
|
|
|
|
{players.length === 0 && (
|
|
<Text ta="center" c="dimmed" py="xl">
|
|
<Trans>No player activity found</Trans>
|
|
</Text>
|
|
)}
|
|
</Stack>
|
|
</Container>
|
|
);
|
|
};
|