mirror of
https://github.com/wanderer-industries/wanderer
synced 2025-12-12 02:35:42 +00:00
refactor: split up node hooks (#173)
Some checks failed
Build / 🚀 Deploy to test env (fly.io) (push) Has been cancelled
Build / Manual Approval (push) Has been cancelled
Build / 🛠 Build (1.17, 18.x, 27) (push) Has been cancelled
Build / 🛠 Build Docker Images (linux/amd64) (push) Has been cancelled
Build / 🛠 Build Docker Images (linux/arm64) (push) Has been cancelled
Build / merge (push) Has been cancelled
Build / 🏷 Create Release (push) Has been cancelled
Some checks failed
Build / 🚀 Deploy to test env (fly.io) (push) Has been cancelled
Build / Manual Approval (push) Has been cancelled
Build / 🛠 Build (1.17, 18.x, 27) (push) Has been cancelled
Build / 🛠 Build Docker Images (linux/amd64) (push) Has been cancelled
Build / 🛠 Build Docker Images (linux/arm64) (push) Has been cancelled
Build / merge (push) Has been cancelled
Build / 🏷 Create Release (push) Has been cancelled
This commit is contained in:
@@ -4,7 +4,7 @@ import { Handle, NodeProps, Position } from 'reactflow';
|
|||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import classes from './SolarSystemNodeDefault.module.scss';
|
import classes from './SolarSystemNodeDefault.module.scss';
|
||||||
import { PrimeIcons } from 'primereact/api';
|
import { PrimeIcons } from 'primereact/api';
|
||||||
import { useLocalCounter, useSolarSystemNode, useNodeKillsCount } from '../../hooks/useSolarSystemLogic';
|
import { useLocalCounter, useSolarSystemNode, useNodeKillsCount } from '../../hooks';
|
||||||
import {
|
import {
|
||||||
EFFECT_BACKGROUND_STYLES,
|
EFFECT_BACKGROUND_STYLES,
|
||||||
MARKER_BOOKMARK_BG_STYLES,
|
MARKER_BOOKMARK_BG_STYLES,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Handle, NodeProps, Position } from 'reactflow';
|
|||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import classes from './SolarSystemNodeTheme.module.scss';
|
import classes from './SolarSystemNodeTheme.module.scss';
|
||||||
import { PrimeIcons } from 'primereact/api';
|
import { PrimeIcons } from 'primereact/api';
|
||||||
import { useLocalCounter, useNodeKillsCount, useSolarSystemNode } from '../../hooks/useSolarSystemLogic';
|
import { useLocalCounter, useNodeKillsCount, useSolarSystemNode } from '../../hooks';
|
||||||
import {
|
import {
|
||||||
EFFECT_BACKGROUND_STYLES,
|
EFFECT_BACKGROUND_STYLES,
|
||||||
MARKER_BOOKMARK_BG_STYLES,
|
MARKER_BOOKMARK_BG_STYLES,
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
export * from './useMapHandlers';
|
export * from './useMapHandlers';
|
||||||
export * from './useUpdateNodes';
|
export * from './useUpdateNodes';
|
||||||
export * from './useNodesEdgesState';
|
export * from './useNodesEdgesState';
|
||||||
|
export * from './useBackgroundVars';
|
||||||
|
export * from './useKillsCounter';
|
||||||
|
export * from './useSystemName';
|
||||||
|
export * from './useNodesEdgesState';
|
||||||
|
export * from './useSolarSystemNode';
|
||||||
|
export * from './useUnsplashedSignatures';
|
||||||
|
export * from './useUpdateNodes';
|
||||||
|
export * from './useNodeKillsCount';
|
||||||
|
|||||||
31
assets/js/hooks/Mapper/components/map/hooks/useLabelsInfo.ts
Normal file
31
assets/js/hooks/Mapper/components/map/hooks/useLabelsInfo.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
|
import { LabelsManager } from '@/hooks/Mapper/utils/labelsManager';
|
||||||
|
import { LABELS_INFO, LABELS_ORDER } from '@/hooks/Mapper/components/map/constants';
|
||||||
|
interface UseLabelsInfoParams {
|
||||||
|
labels: string | null;
|
||||||
|
linkedSigPrefix: string | null;
|
||||||
|
isShowLinkedSigId: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LabelInfo = {
|
||||||
|
id: string;
|
||||||
|
shortName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
function sortedLabels(labels: string[]): LabelInfo[] {
|
||||||
|
if (!labels) return [];
|
||||||
|
return LABELS_ORDER.filter(x => labels.includes(x)).map(x => LABELS_INFO[x] as LabelInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useLabelsInfo({ labels, linkedSigPrefix, isShowLinkedSigId }: UseLabelsInfoParams) {
|
||||||
|
const labelsManager = useMemo(() => new LabelsManager(labels ?? ''), [labels]);
|
||||||
|
const labelsInfo = useMemo(() => sortedLabels(labelsManager.list), [labelsManager]);
|
||||||
|
const labelCustom = useMemo(() => {
|
||||||
|
if (isShowLinkedSigId && linkedSigPrefix) {
|
||||||
|
return labelsManager.customLabel ? `${linkedSigPrefix}・${labelsManager.customLabel}` : linkedSigPrefix;
|
||||||
|
}
|
||||||
|
return labelsManager.customLabel;
|
||||||
|
}, [linkedSigPrefix, isShowLinkedSigId, labelsManager]);
|
||||||
|
|
||||||
|
return { labelsInfo, labelCustom };
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { useEffect, useState, useCallback } from 'react';
|
||||||
|
import { useMapEventListener } from '@/hooks/Mapper/events';
|
||||||
|
import { Commands } from '@/hooks/Mapper/types';
|
||||||
|
|
||||||
|
interface Kill {
|
||||||
|
solar_system_id: number | string;
|
||||||
|
kills: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MapEvent {
|
||||||
|
name: Commands;
|
||||||
|
data?: any;
|
||||||
|
payload?: Kill[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useNodeKillsCount(
|
||||||
|
systemId: number | string,
|
||||||
|
initialKillsCount: number | null
|
||||||
|
): number | null {
|
||||||
|
const [killsCount, setKillsCount] = useState<number | null>(initialKillsCount);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setKillsCount(initialKillsCount);
|
||||||
|
}, [initialKillsCount]);
|
||||||
|
|
||||||
|
const handleEvent = useCallback((event: MapEvent): boolean => {
|
||||||
|
if (event.name === Commands.killsUpdated && Array.isArray(event.payload)) {
|
||||||
|
const killForSystem = event.payload.find(
|
||||||
|
kill => kill.solar_system_id.toString() === systemId.toString()
|
||||||
|
);
|
||||||
|
if (killForSystem && typeof killForSystem.kills === 'number') {
|
||||||
|
setKillsCount(killForSystem.kills);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}, [systemId]);
|
||||||
|
|
||||||
|
useMapEventListener(handleEvent);
|
||||||
|
|
||||||
|
return killsCount;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { MapSolarSystemType } from '../map.types';
|
import { MapSolarSystemType } from '../map.types';
|
||||||
import { NodeProps } from 'reactflow';
|
import { NodeProps } from 'reactflow';
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
@@ -7,19 +7,12 @@ import { useMapState } from '@/hooks/Mapper/components/map/MapProvider';
|
|||||||
import { useDoubleClick } from '@/hooks/Mapper/hooks/useDoubleClick';
|
import { useDoubleClick } from '@/hooks/Mapper/hooks/useDoubleClick';
|
||||||
import { REGIONS_MAP, Spaces } from '@/hooks/Mapper/constants';
|
import { REGIONS_MAP, Spaces } from '@/hooks/Mapper/constants';
|
||||||
import { isWormholeSpace } from '@/hooks/Mapper/components/map/helpers/isWormholeSpace';
|
import { isWormholeSpace } from '@/hooks/Mapper/components/map/helpers/isWormholeSpace';
|
||||||
import { getSystemClassStyles, prepareUnsplashedChunks } from '@/hooks/Mapper/components/map/helpers';
|
import { getSystemClassStyles } from '@/hooks/Mapper/components/map/helpers';
|
||||||
import { sortWHClasses } from '@/hooks/Mapper/helpers';
|
import { sortWHClasses } from '@/hooks/Mapper/helpers';
|
||||||
import { LabelsManager } from '@/hooks/Mapper/utils/labelsManager';
|
import { CharacterTypeRaw, OutCommand, SystemSignature } from '@/hooks/Mapper/types';
|
||||||
import { CharacterTypeRaw, Commands, OutCommand, SystemSignature } from '@/hooks/Mapper/types';
|
import { useUnsplashedSignatures } from './useUnsplashedSignatures';
|
||||||
import { LABELS_INFO, LABELS_ORDER } from '@/hooks/Mapper/components/map/constants';
|
import { useSystemName } from './useSystemName';
|
||||||
import { useMapEventListener } from '@/hooks/Mapper/events';
|
import { LabelInfo, useLabelsInfo } from './useLabelsInfo';
|
||||||
|
|
||||||
export type LabelInfo = {
|
|
||||||
id: string;
|
|
||||||
shortName: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type UnsplashedSignatureType = SystemSignature & { sig_id: string };
|
|
||||||
|
|
||||||
function getActivityType(count: number): string {
|
function getActivityType(count: number): string {
|
||||||
if (count <= 5) return 'activityNormal';
|
if (count <= 5) return 'activityNormal';
|
||||||
@@ -34,11 +27,6 @@ const SpaceToClass: Record<string, string> = {
|
|||||||
[Spaces.Gallente]: 'Gallente',
|
[Spaces.Gallente]: 'Gallente',
|
||||||
};
|
};
|
||||||
|
|
||||||
function sortedLabels(labels: string[]): LabelInfo[] {
|
|
||||||
if (!labels) return [];
|
|
||||||
return LABELS_ORDER.filter(x => labels.includes(x)).map(x => LABELS_INFO[x] as LabelInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useLocalCounter(nodeVars: SolarSystemNodeVars) {
|
export function useLocalCounter(nodeVars: SolarSystemNodeVars) {
|
||||||
const localCounterCharacters = useMemo(() => {
|
const localCounterCharacters = useMemo(() => {
|
||||||
return nodeVars.charactersInSystem
|
return nodeVars.charactersInSystem
|
||||||
@@ -127,21 +115,19 @@ export function useSolarSystemNode(props: NodeProps<MapSolarSystemType>): SolarS
|
|||||||
|
|
||||||
const linkedSigPrefix = useMemo(() => (linkedSigEveId ? linkedSigEveId.split('-')[0] : null), [linkedSigEveId]);
|
const linkedSigPrefix = useMemo(() => (linkedSigEveId ? linkedSigEveId.split('-')[0] : null), [linkedSigEveId]);
|
||||||
|
|
||||||
const labelsManager = useMemo(() => new LabelsManager(labels ?? ''), [labels]);
|
const { labelsInfo, labelCustom } = useLabelsInfo({
|
||||||
const labelsInfo = useMemo(() => sortedLabels(labelsManager.list), [labelsManager]);
|
labels,
|
||||||
const labelCustom = useMemo(() => {
|
linkedSigPrefix,
|
||||||
if (isShowLinkedSigId && linkedSigPrefix) {
|
isShowLinkedSigId,
|
||||||
return labelsManager.customLabel ? `${linkedSigPrefix}・${labelsManager.customLabel}` : linkedSigPrefix;
|
});
|
||||||
}
|
|
||||||
return labelsManager.customLabel;
|
|
||||||
}, [linkedSigPrefix, isShowLinkedSigId, labelsManager]);
|
|
||||||
|
|
||||||
const killsCount = useMemo(() => kills[solar_system_id] ?? null, [kills, solar_system_id]);
|
const killsCount = useMemo(() => kills[solar_system_id] ?? null, [kills, solar_system_id]);
|
||||||
const killsActivityType = killsCount ? getActivityType(killsCount) : null;
|
const killsActivityType = killsCount ? getActivityType(killsCount) : null;
|
||||||
|
|
||||||
const hasUserCharacters = useMemo(() => {
|
const hasUserCharacters = useMemo(
|
||||||
return charactersInSystem.some(x => userCharacters.includes(x.eve_id));
|
() => charactersInSystem.some(x => userCharacters.includes(x.eve_id)),
|
||||||
}, [charactersInSystem, userCharacters]);
|
[charactersInSystem, userCharacters],
|
||||||
|
);
|
||||||
|
|
||||||
const dbClick = useDoubleClick(() => {
|
const dbClick = useDoubleClick(() => {
|
||||||
outCommand({
|
outCommand({
|
||||||
@@ -153,54 +139,19 @@ export function useSolarSystemNode(props: NodeProps<MapSolarSystemType>): SolarS
|
|||||||
const showHandlers = isConnecting || hoverNodeId === id;
|
const showHandlers = isConnecting || hoverNodeId === id;
|
||||||
|
|
||||||
const space = showKSpaceBG ? REGIONS_MAP[region_id] : '';
|
const space = showKSpaceBG ? REGIONS_MAP[region_id] : '';
|
||||||
const regionClass = showKSpaceBG ? SpaceToClass[space] : null;
|
const regionClass = showKSpaceBG ? SpaceToClass[space] || null : null;
|
||||||
|
|
||||||
const computedTemporaryName = useMemo(() => {
|
const { systemName, computedTemporaryName, customName } = useSystemName({
|
||||||
if (!isTempSystemNameEnabled) {
|
isTempSystemNameEnabled,
|
||||||
return '';
|
temporary_name,
|
||||||
}
|
solar_system_name: solar_system_name || '',
|
||||||
if (isShowLinkedSigIdTempName && linkedSigPrefix) {
|
isShowLinkedSigIdTempName,
|
||||||
return temporary_name ? `${linkedSigPrefix}・${temporary_name}` : `${linkedSigPrefix}・${solar_system_name}`;
|
linkedSigPrefix,
|
||||||
}
|
name,
|
||||||
return temporary_name;
|
});
|
||||||
}, [isShowLinkedSigIdTempName, isTempSystemNameEnabled, linkedSigPrefix, solar_system_name, temporary_name]);
|
|
||||||
|
|
||||||
const systemName = useMemo(() => {
|
const { unsplashedLeft, unsplashedRight } = useUnsplashedSignatures(systemSigs, isShowUnsplashedSignatures);
|
||||||
if (isTempSystemNameEnabled && computedTemporaryName) {
|
|
||||||
return computedTemporaryName;
|
|
||||||
}
|
|
||||||
return solar_system_name;
|
|
||||||
}, [isTempSystemNameEnabled, solar_system_name, computedTemporaryName]);
|
|
||||||
|
|
||||||
const customName = useMemo(() => {
|
|
||||||
if (isTempSystemNameEnabled && computedTemporaryName && name) {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
if (solar_system_name !== name && name) {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}, [isTempSystemNameEnabled, computedTemporaryName, name, solar_system_name]);
|
|
||||||
|
|
||||||
const [unsplashedLeft, unsplashedRight] = useMemo(() => {
|
|
||||||
if (!isShowUnsplashedSignatures) {
|
|
||||||
return [[], []];
|
|
||||||
}
|
|
||||||
return prepareUnsplashedChunks(
|
|
||||||
systemSigs
|
|
||||||
.filter(s => s.group === 'Wormhole' && !s.linked_system)
|
|
||||||
.map(s => ({
|
|
||||||
eve_id: s.eve_id,
|
|
||||||
type: s.type,
|
|
||||||
custom_info: s.custom_info,
|
|
||||||
kind: s.kind,
|
|
||||||
name: s.name,
|
|
||||||
group: s.group,
|
|
||||||
})) as UnsplashedSignatureType[],
|
|
||||||
);
|
|
||||||
}, [isShowUnsplashedSignatures, systemSigs]);
|
|
||||||
|
|
||||||
// Ensure hubs are always strings.
|
|
||||||
const hubsAsStrings = useMemo(() => hubs.map(item => item.toString()), [hubs]);
|
const hubsAsStrings = useMemo(() => hubs.map(item => item.toString()), [hubs]);
|
||||||
|
|
||||||
const nodeVars: SolarSystemNodeVars = {
|
const nodeVars: SolarSystemNodeVars = {
|
||||||
@@ -225,12 +176,10 @@ export function useSolarSystemNode(props: NodeProps<MapSolarSystemType>): SolarS
|
|||||||
dbClick,
|
dbClick,
|
||||||
sortedStatics,
|
sortedStatics,
|
||||||
effectName: effect_name,
|
effectName: effect_name,
|
||||||
regionName: region_name,
|
|
||||||
solarSystemId: solar_system_id.toString(),
|
solarSystemId: solar_system_id.toString(),
|
||||||
solarSystemName: solar_system_name,
|
|
||||||
locked,
|
locked,
|
||||||
hubs: hubsAsStrings,
|
hubs: hubsAsStrings,
|
||||||
name: name,
|
name,
|
||||||
isConnecting,
|
isConnecting,
|
||||||
hoverNodeId,
|
hoverNodeId,
|
||||||
charactersInSystem,
|
charactersInSystem,
|
||||||
@@ -239,6 +188,8 @@ export function useSolarSystemNode(props: NodeProps<MapSolarSystemType>): SolarS
|
|||||||
isThickConnections,
|
isThickConnections,
|
||||||
classTitle: class_title,
|
classTitle: class_title,
|
||||||
temporaryName: computedTemporaryName,
|
temporaryName: computedTemporaryName,
|
||||||
|
regionName: region_name,
|
||||||
|
solarSystemName: solar_system_name,
|
||||||
};
|
};
|
||||||
|
|
||||||
return nodeVars;
|
return nodeVars;
|
||||||
@@ -281,25 +232,3 @@ export interface SolarSystemNodeVars {
|
|||||||
classTitle: string | null;
|
classTitle: string | null;
|
||||||
temporaryName?: string | null;
|
temporaryName?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useNodeKillsCount(systemId: number | string, initialKillsCount: number | null): number | null {
|
|
||||||
const [killsCount, setKillsCount] = useState<number | null>(initialKillsCount);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setKillsCount(initialKillsCount);
|
|
||||||
}, [initialKillsCount]);
|
|
||||||
|
|
||||||
useMapEventListener(event => {
|
|
||||||
if (event.name === Commands.killsUpdated && event.data?.toString() === systemId.toString()) {
|
|
||||||
//@ts-ignore
|
|
||||||
if (event.payload && typeof event.payload.kills === 'number') {
|
|
||||||
// @ts-ignore
|
|
||||||
setKillsCount(event.payload.kills);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
return killsCount;
|
|
||||||
}
|
|
||||||
49
assets/js/hooks/Mapper/components/map/hooks/useSystemName.ts
Normal file
49
assets/js/hooks/Mapper/components/map/hooks/useSystemName.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// useSystemName.ts
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
|
interface UseSystemNameParams {
|
||||||
|
isTempSystemNameEnabled: boolean;
|
||||||
|
temporary_name?: string | null;
|
||||||
|
solar_system_name: string;
|
||||||
|
isShowLinkedSigIdTempName: boolean;
|
||||||
|
linkedSigPrefix: string | null;
|
||||||
|
name?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useSystemName({
|
||||||
|
isTempSystemNameEnabled,
|
||||||
|
temporary_name,
|
||||||
|
solar_system_name,
|
||||||
|
isShowLinkedSigIdTempName,
|
||||||
|
linkedSigPrefix,
|
||||||
|
name,
|
||||||
|
}: UseSystemNameParams) {
|
||||||
|
const computedTemporaryName = useMemo(() => {
|
||||||
|
if (!isTempSystemNameEnabled) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (isShowLinkedSigIdTempName && linkedSigPrefix) {
|
||||||
|
return temporary_name ? `${linkedSigPrefix}・${temporary_name}` : `${linkedSigPrefix}・${solar_system_name}`;
|
||||||
|
}
|
||||||
|
return temporary_name ?? '';
|
||||||
|
}, [isTempSystemNameEnabled, temporary_name, solar_system_name, isShowLinkedSigIdTempName, linkedSigPrefix]);
|
||||||
|
|
||||||
|
const systemName = useMemo(() => {
|
||||||
|
if (isTempSystemNameEnabled && computedTemporaryName) {
|
||||||
|
return computedTemporaryName;
|
||||||
|
}
|
||||||
|
return solar_system_name;
|
||||||
|
}, [isTempSystemNameEnabled, computedTemporaryName, solar_system_name]);
|
||||||
|
|
||||||
|
const customName = useMemo(() => {
|
||||||
|
if (isTempSystemNameEnabled && computedTemporaryName && name) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
if (solar_system_name !== name && name) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}, [isTempSystemNameEnabled, computedTemporaryName, name, solar_system_name]);
|
||||||
|
|
||||||
|
return { systemName, computedTemporaryName, customName };
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
|
import { SystemSignature } from '@/hooks/Mapper/types';
|
||||||
|
import { prepareUnsplashedChunks } from '@/hooks/Mapper/components/map/helpers';
|
||||||
|
|
||||||
|
export type UnsplashedSignatureType = SystemSignature & { sig_id: string };
|
||||||
|
|
||||||
|
export function useUnsplashedSignatures(systemSigs: SystemSignature[], isShowUnsplashedSignatures: boolean) {
|
||||||
|
return useMemo(() => {
|
||||||
|
if (!isShowUnsplashedSignatures) {
|
||||||
|
return {
|
||||||
|
unsplashedLeft: [] as SystemSignature[],
|
||||||
|
unsplashedRight: [] as SystemSignature[],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const chunks = prepareUnsplashedChunks(
|
||||||
|
systemSigs
|
||||||
|
.filter(s => s.group === 'Wormhole' && !s.linked_system)
|
||||||
|
.map(s => ({
|
||||||
|
eve_id: s.eve_id,
|
||||||
|
type: s.type,
|
||||||
|
custom_info: s.custom_info,
|
||||||
|
kind: s.kind,
|
||||||
|
name: s.name,
|
||||||
|
group: s.group,
|
||||||
|
})) as UnsplashedSignatureType[],
|
||||||
|
);
|
||||||
|
const [unsplashedLeft, unsplashedRight] = chunks;
|
||||||
|
return { unsplashedLeft, unsplashedRight };
|
||||||
|
}, [isShowUnsplashedSignatures, systemSigs]);
|
||||||
|
}
|
||||||
@@ -6,9 +6,9 @@ import { SolarSystemRawType } from '@/hooks/Mapper/types';
|
|||||||
const useThrottle = () => {
|
const useThrottle = () => {
|
||||||
const throttleSeed = useRef<number | null>(null);
|
const throttleSeed = useRef<number | null>(null);
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const throttleFunction = useRef((func: any, delay = 200) => {
|
const throttleFunction = useRef((func: any, delay = 200) => {
|
||||||
if (!throttleSeed.current) {
|
if (!throttleSeed.current) {
|
||||||
// Call the callback immediately for the first time
|
|
||||||
func();
|
func();
|
||||||
throttleSeed.current = setTimeout(() => {
|
throttleSeed.current = setTimeout(() => {
|
||||||
throttleSeed.current = null;
|
throttleSeed.current = null;
|
||||||
@@ -75,7 +75,7 @@ export const useUpdateNodes = (nodes: Node<SolarSystemRawType>[]) => {
|
|||||||
|
|
||||||
const visibleNodes = new Set(nodes.filter(x => isNodeVisible(x, viewport)).map(x => x.id));
|
const visibleNodes = new Set(nodes.filter(x => isNodeVisible(x, viewport)).map(x => x.id));
|
||||||
update({ visibleNodes });
|
update({ visibleNodes });
|
||||||
}, [nodes]);
|
}, [getViewport, nodes, update]);
|
||||||
|
|
||||||
useOnViewportChange({
|
useOnViewportChange({
|
||||||
onChange: () => throttle(updateNodesVisibility.bind(this)),
|
onChange: () => throttle(updateNodesVisibility.bind(this)),
|
||||||
@@ -84,5 +84,5 @@ export const useUpdateNodes = (nodes: Node<SolarSystemRawType>[]) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateNodesVisibility();
|
updateNodesVisibility();
|
||||||
}, [nodes]);
|
}, [nodes, updateNodesVisibility]);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { useCallback, useMemo, useState, useEffect, useRef } from 'react';
|
import { useCallback, useMemo, useState, useEffect, useRef } from 'react';
|
||||||
import debounce from 'lodash.debounce';
|
import debounce from 'lodash.debounce';
|
||||||
import { OutCommand } from '@/hooks/Mapper/types/mapHandlers';
|
import { Commands, OutCommand } from '@/hooks/Mapper/types/mapHandlers';
|
||||||
import { DetailedKill } from '@/hooks/Mapper/types/kills';
|
import { DetailedKill } from '@/hooks/Mapper/types/kills';
|
||||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||||
import { useKillsWidgetSettings } from './useKillsWidgetSettings';
|
import { useKillsWidgetSettings } from './useKillsWidgetSettings';
|
||||||
|
import { useMapEventListener, MapEvent } from '@/hooks/Mapper/events';
|
||||||
|
|
||||||
interface UseSystemKillsProps {
|
interface UseSystemKillsProps {
|
||||||
systemId?: string;
|
systemId?: string;
|
||||||
@@ -13,16 +14,17 @@ interface UseSystemKillsProps {
|
|||||||
sinceHours?: number;
|
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 cutoff = Date.now() - sinceHours * 60 * 60 * 1000;
|
||||||
const byId: Record<string, DetailedKill> = {};
|
const byId: Record<string, DetailedKill> = {};
|
||||||
|
|
||||||
for (const kill of [...existing, ...incoming]) {
|
for (const kill of [...existing, ...incoming]) {
|
||||||
if (!kill.kill_time) {
|
if (!kill.kill_time) continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const killTimeMs = new Date(kill.kill_time).valueOf();
|
const killTimeMs = new Date(kill.kill_time).valueOf();
|
||||||
|
|
||||||
if (killTimeMs >= cutoff) {
|
if (killTimeMs >= cutoff) {
|
||||||
byId[kill.killmail_id] = kill;
|
byId[kill.killmail_id] = kill;
|
||||||
}
|
}
|
||||||
@@ -31,30 +33,57 @@ function combineKills(existing: DetailedKill[], incoming: DetailedKill[], sinceH
|
|||||||
return Object.values(byId);
|
return Object.values(byId);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useSystemKills({ systemId, outCommand, showAllVisible = false, sinceHours = 24 }: UseSystemKillsProps) {
|
interface DetailedKillsEvent extends MapEvent<Commands> {
|
||||||
|
payload: Record<string, DetailedKill[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useSystemKills({
|
||||||
|
systemId,
|
||||||
|
outCommand,
|
||||||
|
showAllVisible = false,
|
||||||
|
sinceHours = 24,
|
||||||
|
}: UseSystemKillsProps) {
|
||||||
const { data, update } = useMapRootState();
|
const { data, update } = useMapRootState();
|
||||||
const { detailedKills = {}, systems = [] } = data;
|
const { detailedKills = {}, systems = [] } = data;
|
||||||
|
|
||||||
const [settings] = useKillsWidgetSettings();
|
const [settings] = useKillsWidgetSettings();
|
||||||
const excludedSystems = settings.excludedSystems;
|
const excludedSystems = settings.excludedSystems;
|
||||||
|
|
||||||
// When showing all visible kills, filter out excluded systems;
|
const updateDetailedKills = useCallback((newKillsMap: Record<string, DetailedKill[]>) => {
|
||||||
// when showAllVisible is false, ignore the exclusion filter.
|
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) {
|
||||||
|
const detailedEvent = event as DetailedKillsEvent;
|
||||||
|
if (systemId && !Object.keys(detailedEvent.payload).includes(systemId.toString())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
updateDetailedKills(detailedEvent.payload);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
const effectiveSystemIds = useMemo(() => {
|
const effectiveSystemIds = useMemo(() => {
|
||||||
if (showAllVisible) {
|
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]);
|
}, [systems, excludedSystems, showAllVisible]);
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
const didFallbackFetch = useRef(Object.keys(detailedKills).length !== 0);
|
const didFallbackFetch = useRef(Object.keys(detailedKills).length !== 0);
|
||||||
|
|
||||||
const mergeKillsIntoGlobal = useCallback(
|
const mergeKillsIntoGlobal = useCallback((killsMap: Record<string, DetailedKill[]>) => {
|
||||||
(killsMap: Record<string, DetailedKill[]>) => {
|
update((prev) => {
|
||||||
update(prev => {
|
|
||||||
const oldMap = prev.detailedKills ?? {};
|
const oldMap = prev.detailedKills ?? {};
|
||||||
const updated: Record<string, DetailedKill[]> = { ...oldMap };
|
const updated: Record<string, DetailedKill[]> = { ...oldMap };
|
||||||
|
|
||||||
@@ -64,17 +93,11 @@ export function useSystemKills({ systemId, outCommand, showAllVisible = false, s
|
|||||||
updated[sid] = combined;
|
updated[sid] = combined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return { ...prev, detailedKills: updated };
|
||||||
...prev,
|
|
||||||
detailedKills: updated,
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
},
|
}, [update, sinceHours]);
|
||||||
[update, sinceHours],
|
|
||||||
);
|
|
||||||
|
|
||||||
const fetchKills = useCallback(
|
const fetchKills = useCallback(async (forceFallback = false) => {
|
||||||
async (forceFallback = false) => {
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
@@ -95,7 +118,6 @@ export function useSystemKills({ systemId, outCommand, showAllVisible = false, s
|
|||||||
since_hours: sinceHours,
|
since_hours: sinceHours,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
// If there's no system and not showing all, do nothing
|
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -105,13 +127,11 @@ export function useSystemKills({ systemId, outCommand, showAllVisible = false, s
|
|||||||
data: requestData,
|
data: requestData,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Single system => `resp.kills`
|
|
||||||
if (resp?.kills) {
|
if (resp?.kills) {
|
||||||
const arr = resp.kills as DetailedKill[];
|
const arr = resp.kills as DetailedKill[];
|
||||||
const sid = systemId ?? 'unknown';
|
const sid = systemId ?? 'unknown';
|
||||||
mergeKillsIntoGlobal({ [sid]: arr });
|
mergeKillsIntoGlobal({ [sid]: arr });
|
||||||
}
|
}
|
||||||
// multiple systems => `resp.systems_kills`
|
|
||||||
else if (resp?.systems_kills) {
|
else if (resp?.systems_kills) {
|
||||||
mergeKillsIntoGlobal(resp.systems_kills as Record<string, DetailedKill[]>);
|
mergeKillsIntoGlobal(resp.systems_kills as Record<string, DetailedKill[]>);
|
||||||
} else {
|
} else {
|
||||||
@@ -123,9 +143,7 @@ export function useSystemKills({ systemId, outCommand, showAllVisible = false, s
|
|||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
},
|
}, [showAllVisible, systemId, outCommand, effectiveSystemIds, sinceHours, mergeKillsIntoGlobal]);
|
||||||
[showAllVisible, systemId, outCommand, effectiveSystemIds, sinceHours, mergeKillsIntoGlobal],
|
|
||||||
);
|
|
||||||
|
|
||||||
const debouncedFetchKills = useMemo(
|
const debouncedFetchKills = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@@ -138,12 +156,11 @@ export function useSystemKills({ systemId, outCommand, showAllVisible = false, s
|
|||||||
|
|
||||||
const finalKills = useMemo(() => {
|
const finalKills = useMemo(() => {
|
||||||
if (showAllVisible) {
|
if (showAllVisible) {
|
||||||
return effectiveSystemIds.flatMap(sid => detailedKills[sid] ?? []);
|
return effectiveSystemIds.flatMap((sid) => detailedKills[sid] ?? []);
|
||||||
} else if (systemId) {
|
} else if (systemId) {
|
||||||
return detailedKills[systemId] ?? [];
|
return detailedKills[systemId] ?? [];
|
||||||
} else if (didFallbackFetch.current) {
|
} else if (didFallbackFetch.current) {
|
||||||
// if we already did a fallback, we may have data for multiple systems
|
return effectiveSystemIds.flatMap((sid) => detailedKills[sid] ?? []);
|
||||||
return effectiveSystemIds.flatMap(sid => detailedKills[sid] ?? []);
|
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
}, [showAllVisible, systemId, effectiveSystemIds, detailedKills]);
|
}, [showAllVisible, systemId, effectiveSystemIds, detailedKills]);
|
||||||
@@ -153,9 +170,8 @@ export function useSystemKills({ systemId, outCommand, showAllVisible = false, s
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!systemId && !showAllVisible && !didFallbackFetch.current) {
|
if (!systemId && !showAllVisible && !didFallbackFetch.current) {
|
||||||
didFallbackFetch.current = true;
|
didFallbackFetch.current = true;
|
||||||
// Cancel any queued debounced calls, then do the fallback.
|
|
||||||
debouncedFetchKills.cancel();
|
debouncedFetchKills.cancel();
|
||||||
fetchKills(true); // forceFallback => fetch as though showAllVisible is true
|
fetchKills(true);
|
||||||
}
|
}
|
||||||
}, [systemId, showAllVisible, debouncedFetchKills, fetchKills]);
|
}, [systemId, showAllVisible, debouncedFetchKills, fetchKills]);
|
||||||
|
|
||||||
@@ -164,14 +180,13 @@ export function useSystemKills({ systemId, outCommand, showAllVisible = false, s
|
|||||||
|
|
||||||
if (showAllVisible || systemId) {
|
if (showAllVisible || systemId) {
|
||||||
debouncedFetchKills();
|
debouncedFetchKills();
|
||||||
// Clean up the debounce on unmount or changes
|
|
||||||
return () => debouncedFetchKills.cancel();
|
return () => debouncedFetchKills.cancel();
|
||||||
}
|
}
|
||||||
}, [showAllVisible, systemId, effectiveSystemIds, debouncedFetchKills]);
|
}, [showAllVisible, systemId, effectiveSystemIds, debouncedFetchKills]);
|
||||||
|
|
||||||
const refetch = useCallback(() => {
|
const refetch = useCallback(() => {
|
||||||
debouncedFetchKills.cancel();
|
debouncedFetchKills.cancel();
|
||||||
fetchKills(); // immediate (non-debounced) call
|
fetchKills();
|
||||||
}, [debouncedFetchKills, fetchKills]);
|
}, [debouncedFetchKills, fetchKills]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user