mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-15 07:24:52 +09:00
Every view page handled a resource that can't be shown its own way, and users without the subscribe permission were left on a spinner forever. Adds useResourceState and a ResourceState component, used by the host, instance, mod pack, icon reference, user, role and plugin pages and exported for plugin pages. The single item hooks now also return the subscription error. Resolves #1165
101 lines
3.1 KiB
TypeScript
101 lines
3.1 KiB
TypeScript
import React, { useCallback, useContext, useSyncExternalStore } from "react";
|
|
import { Tag } from "antd";
|
|
import ControlContext from "../components/ControlContext";
|
|
|
|
import * as lib from "@clusterio/lib";
|
|
|
|
export function getUserStats(user: lib.UserDetails, instanceId?: number) {
|
|
if (instanceId === undefined) {
|
|
return user.playerStats;
|
|
}
|
|
return user.instanceStats.get(instanceId);
|
|
}
|
|
|
|
export function isUserOnline(user: lib.UserDetails, instanceId?: number) {
|
|
if (instanceId === undefined) {
|
|
return user.instances && user.instances.size > 0;
|
|
}
|
|
return user.instances && user.instances.has(instanceId);
|
|
}
|
|
|
|
export function calculateFirstSeen(user: lib.UserDetails, instanceId?: number) {
|
|
const stats = getUserStats(user, instanceId);
|
|
return stats?.firstJoinAt?.getTime();
|
|
}
|
|
|
|
export function calculateLastSeen(user: lib.UserDetails, instanceId?: number) {
|
|
const stats = getUserStats(user, instanceId);
|
|
if (!stats) {
|
|
return undefined;
|
|
}
|
|
if (stats.lastLeaveAt && stats.lastLeaveAt.getTime() > (stats.lastJoinAt?.getTime() ?? 0)) {
|
|
return stats.lastLeaveAt.getTime();
|
|
}
|
|
if (stats.lastJoinAt) {
|
|
return stats.lastJoinAt.getTime();
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
export function formatFirstSeen(user: lib.UserDetails, instanceId?: number) {
|
|
const firstSeen = calculateFirstSeen(user, instanceId);
|
|
if (firstSeen === undefined) {
|
|
return undefined;
|
|
}
|
|
return new Date(firstSeen).toLocaleString();
|
|
}
|
|
|
|
export function formatLastSeen(user: lib.UserDetails, instanceId?: number) {
|
|
if (user.instances && [...user.instances].some(id => instanceId === undefined || id === instanceId)) {
|
|
return <Tag color="green">Online</Tag>;
|
|
}
|
|
let lastSeen = calculateLastSeen(user, instanceId);
|
|
if (lastSeen === undefined) {
|
|
return undefined;
|
|
}
|
|
return new Date(lastSeen).toLocaleString();
|
|
}
|
|
|
|
export function sortFirstSeen(
|
|
userA: lib.UserDetails,
|
|
userB: lib.UserDetails,
|
|
instanceIdA?: number,
|
|
instanceIdB?: number
|
|
) {
|
|
const firstSeenA = calculateFirstSeen(userA, instanceIdA) || 0;
|
|
const firstSeenB = calculateFirstSeen(userB, instanceIdB) || 0;
|
|
return firstSeenA - firstSeenB;
|
|
}
|
|
|
|
export function sortLastSeen(
|
|
userA: lib.UserDetails,
|
|
userB: lib.UserDetails,
|
|
instanceIdA?: number,
|
|
instanceIdB?: number
|
|
) {
|
|
function epoch(user: lib.UserDetails, instanceId?: number) {
|
|
return user.instances && [...user.instances].some(id => instanceId === undefined || id === instanceId);
|
|
}
|
|
|
|
let epochA = epoch(userA, instanceIdA);
|
|
let epochB = epoch(userB, instanceIdB);
|
|
if (epochA !== epochB) {
|
|
return Number(epochA) - Number(epochB);
|
|
}
|
|
|
|
let lastSeenA = calculateLastSeen(userA, instanceIdA) || 0;
|
|
let lastSeenB = calculateLastSeen(userB, instanceIdB) || 0;
|
|
return lastSeenA - lastSeenB;
|
|
}
|
|
|
|
export function useUser(name?: string) {
|
|
const [users, synced, error] = useUsers();
|
|
return [name !== undefined ? users.get(name.toLowerCase()) : undefined, synced, error] as const;
|
|
}
|
|
|
|
export function useUsers() {
|
|
const control = useContext(ControlContext);
|
|
const subscribe = useCallback((callback: () => void) => control.users.subscribe(callback), [control]);
|
|
return useSyncExternalStore(subscribe, () => control.users.getSnapshot());
|
|
}
|