fix: add retry on kills retrieval (#207)

This commit is contained in:
guarzo
2025-03-04 02:13:59 -05:00
committed by GitHub
parent 2da5a243ec
commit 4eb1f641ae
7 changed files with 309 additions and 133 deletions

View File

@@ -2,6 +2,7 @@ import { SystemKillsContent } from '../../../mapInterface/widgets/SystemKills/Sy
import { useKillsCounter } from '../../hooks/useKillsCounter';
import { WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrapper';
import { WithChildren, WithClassName } from '@/hooks/Mapper/types/common';
import { useMemo } from 'react';
type TooltipSize = 'xs' | 'sm' | 'md' | 'lg';
@@ -17,17 +18,44 @@ type KillsBookmarkTooltipProps = {
export const KillsCounter = ({ killsCount, systemId, className, children, size = 'xs' }: KillsBookmarkTooltipProps) => {
const { isLoading, kills: detailedKills, systemNameMap } = useKillsCounter({ realSystemId: systemId });
if (!killsCount || detailedKills.length === 0 || !systemId || isLoading) return null;
// Limit the kills shown to match the killsCount parameter
const limitedKills = useMemo(() => {
if (!detailedKills || detailedKills.length === 0) return [];
return detailedKills.slice(0, killsCount);
}, [detailedKills, killsCount]);
if (!killsCount || limitedKills.length === 0 || !systemId || isLoading) return null;
// Calculate a reasonable height for the tooltip based on the number of kills
// but cap it to avoid excessively large tooltips
const maxKillsToShow = Math.min(limitedKills.length, 20);
const tooltipHeight = Math.max(200, Math.min(500, maxKillsToShow * 35));
const tooltipContent = (
<div style={{ width: '100%', minWidth: '300px', overflow: 'hidden' }}>
<SystemKillsContent
kills={detailedKills}
systemNameMap={systemNameMap}
onlyOneSystem={true}
autoSize={true}
limit={killsCount}
/>
<div
style={{
width: '400px',
height: `${tooltipHeight}px`,
maxHeight: '500px',
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
}}
>
<div className="p-2 border-b border-stone-700 bg-stone-800 text-stone-200 font-medium">
System Kills ({limitedKills.length})
</div>
<div className="flex-1 overflow-hidden">
<SystemKillsContent
kills={limitedKills}
systemNameMap={systemNameMap}
onlyOneSystem={true}
// Don't use autoSize here as we want the virtual scroller to handle scrolling
autoSize={false}
// We've already limited the kills to match killsCount
limit={undefined}
/>
</div>
</div>
);

View File

@@ -27,13 +27,12 @@ export function useKillsCounter({ realSystemId }: UseKillsCounterProps) {
const filteredKills = useMemo(() => {
if (!allKills || allKills.length === 0) return [];
return [...allKills]
.sort((a, b) => {
const aTime = a.kill_time ? new Date(a.kill_time).getTime() : 0;
const bTime = b.kill_time ? new Date(b.kill_time).getTime() : 0;
return bTime - aTime;
})
.slice(0, 10);
// Sort kills by time, most recent first, but don't limit the number of kills
return [...allKills].sort((a, b) => {
const aTime = a.kill_time ? new Date(a.kill_time).getTime() : 0;
const bTime = b.kill_time ? new Date(b.kill_time).getTime() : 0;
return bTime - aTime;
});
}, [allKills]);
return {

View File

@@ -14,11 +14,7 @@ interface UseSystemKillsProps {
sinceHours?: number;
}
function combineKills(
existing: DetailedKill[],
incoming: DetailedKill[],
sinceHours: number
): DetailedKill[] {
function combineKills(existing: DetailedKill[], incoming: DetailedKill[], sinceHours: number): DetailedKill[] {
const cutoff = Date.now() - sinceHours * 60 * 60 * 1000;
const byId: Record<string, DetailedKill> = {};
@@ -37,27 +33,25 @@ interface DetailedKillsEvent extends MapEvent<Commands> {
payload: Record<string, DetailedKill[]>;
}
export function useSystemKills({
systemId,
outCommand,
showAllVisible = false,
sinceHours = 24,
}: UseSystemKillsProps) {
export function useSystemKills({ systemId, outCommand, showAllVisible = false, sinceHours = 24 }: UseSystemKillsProps) {
const { data, update } = useMapRootState();
const { detailedKills = {}, systems = [] } = data;
const [settings] = useKillsWidgetSettings();
const excludedSystems = settings.excludedSystems;
const updateDetailedKills = useCallback((newKillsMap: Record<string, DetailedKill[]>) => {
update((prev) => {
const oldKills = prev.detailedKills ?? {};
const updated = { ...oldKills };
for (const [sid, killsArr] of Object.entries(newKillsMap)) {
updated[sid] = killsArr;
}
return { ...prev, detailedKills: updated };
}, true);
}, [update]);
const updateDetailedKills = useCallback(
(newKillsMap: Record<string, DetailedKill[]>) => {
update(prev => {
const oldKills = prev.detailedKills ?? {};
const updated = { ...oldKills };
for (const [sid, killsArr] of Object.entries(newKillsMap)) {
updated[sid] = killsArr;
}
return { ...prev, detailedKills: updated };
}, true);
},
[update],
);
useMapEventListener((event: MapEvent<Commands>) => {
if (event.name === Commands.detailedKillsUpdated) {
@@ -73,77 +67,82 @@ export function useSystemKills({
const effectiveSystemIds = useMemo(() => {
if (showAllVisible) {
return systems.map((s) => s.id).filter((id) => !excludedSystems.includes(Number(id)));
return systems.map(s => s.id).filter(id => !excludedSystems.includes(Number(id)));
}
return systems.map((s) => s.id);
return systems.map(s => s.id);
}, [systems, excludedSystems, showAllVisible]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const didFallbackFetch = useRef(Object.keys(detailedKills).length !== 0);
const mergeKillsIntoGlobal = useCallback((killsMap: Record<string, DetailedKill[]>) => {
update((prev) => {
const oldMap = prev.detailedKills ?? {};
const updated: Record<string, DetailedKill[]> = { ...oldMap };
const mergeKillsIntoGlobal = useCallback(
(killsMap: Record<string, DetailedKill[]>) => {
update(prev => {
const oldMap = prev.detailedKills ?? {};
const updated: Record<string, DetailedKill[]> = { ...oldMap };
for (const [sid, newKills] of Object.entries(killsMap)) {
const existing = updated[sid] ?? [];
const combined = combineKills(existing, newKills, sinceHours);
updated[sid] = combined;
}
for (const [sid, newKills] of Object.entries(killsMap)) {
const existing = updated[sid] ?? [];
const combined = combineKills(existing, newKills, sinceHours);
updated[sid] = combined;
}
return { ...prev, detailedKills: updated };
});
}, [update, sinceHours]);
const fetchKills = useCallback(async (forceFallback = false) => {
setIsLoading(true);
setError(null);
try {
let eventType: OutCommand;
let requestData: Record<string, unknown>;
if (showAllVisible || forceFallback) {
eventType = OutCommand.getSystemsKills;
requestData = {
system_ids: effectiveSystemIds,
since_hours: sinceHours,
};
} else if (systemId) {
eventType = OutCommand.getSystemKills;
requestData = {
system_id: systemId,
since_hours: sinceHours,
};
} else {
setIsLoading(false);
return;
}
const resp = await outCommand({
type: eventType,
data: requestData,
return { ...prev, detailedKills: updated };
});
},
[update, sinceHours],
);
if (resp?.kills) {
const arr = resp.kills as DetailedKill[];
const sid = systemId ?? 'unknown';
mergeKillsIntoGlobal({ [sid]: arr });
const fetchKills = useCallback(
async (forceFallback = false) => {
setIsLoading(true);
setError(null);
try {
let eventType: OutCommand;
let requestData: Record<string, unknown>;
if (showAllVisible || forceFallback) {
eventType = OutCommand.getSystemsKills;
requestData = {
system_ids: effectiveSystemIds,
since_hours: sinceHours,
};
} else if (systemId) {
eventType = OutCommand.getSystemKills;
requestData = {
system_id: systemId,
since_hours: sinceHours,
};
} else {
setIsLoading(false);
return;
}
const resp = await outCommand({
type: eventType,
data: requestData,
});
if (resp?.kills) {
const arr = resp.kills as DetailedKill[];
const sid = systemId ?? 'unknown';
mergeKillsIntoGlobal({ [sid]: arr });
} else if (resp?.systems_kills) {
mergeKillsIntoGlobal(resp.systems_kills as Record<string, DetailedKill[]>);
} else {
console.warn('[useSystemKills] Unexpected kills response =>', resp);
}
} catch (err) {
console.error('[useSystemKills] Failed to fetch kills:', err);
setError(err instanceof Error ? err.message : 'Error fetching kills');
} finally {
setIsLoading(false);
}
else if (resp?.systems_kills) {
mergeKillsIntoGlobal(resp.systems_kills as Record<string, DetailedKill[]>);
} else {
console.warn('[useSystemKills] Unexpected kills response =>', resp);
}
} catch (err) {
console.error('[useSystemKills] Failed to fetch kills:', err);
setError(err instanceof Error ? err.message : 'Error fetching kills');
} finally {
setIsLoading(false);
}
}, [showAllVisible, systemId, outCommand, effectiveSystemIds, sinceHours, mergeKillsIntoGlobal]);
},
[showAllVisible, systemId, outCommand, effectiveSystemIds, sinceHours, mergeKillsIntoGlobal],
);
const debouncedFetchKills = useMemo(
() =>
@@ -156,11 +155,11 @@ export function useSystemKills({
const finalKills = useMemo(() => {
if (showAllVisible) {
return effectiveSystemIds.flatMap((sid) => detailedKills[sid] ?? []);
return effectiveSystemIds.flatMap(sid => detailedKills[sid] ?? []);
} else if (systemId) {
return detailedKills[systemId] ?? [];
} else if (didFallbackFetch.current) {
return effectiveSystemIds.flatMap((sid) => detailedKills[sid] ?? []);
return effectiveSystemIds.flatMap(sid => detailedKills[sid] ?? []);
}
return [];
}, [showAllVisible, systemId, effectiveSystemIds, detailedKills]);
@@ -171,7 +170,7 @@ export function useSystemKills({
if (!systemId && !showAllVisible && !didFallbackFetch.current) {
didFallbackFetch.current = true;
debouncedFetchKills.cancel();
fetchKills(true);
fetchKills(true);
}
}, [systemId, showAllVisible, debouncedFetchKills, fetchKills]);