Files
goldenChart/frontend/src/hooks/useVirtualTargetRegistry.ts
T
2026-06-01 01:35:31 +09:00

87 lines
2.5 KiB
TypeScript

import { useCallback, useEffect, useMemo, useState } from 'react';
import {
loadVirtualTargets,
VIRTUAL_SESSION_CHANGED_EVENT,
} from '../utils/virtualTradingStorage';
import {
addVirtualTarget,
removeVirtualTarget,
type VirtualTargetMeta,
} from '../utils/virtualTargetMutations';
import { getVirtualTargetMaxCount } from './useAppSettings';
import { virtualTargetLimitMessage } from '../utils/virtualTargetLimits';
/** 가상투자 투자대상 마켓 집합 (추세검색 카드 등) */
export function useVirtualTargetRegistry() {
const [targets, setTargets] = useState(() => loadVirtualTargets());
const [busyMarket, setBusyMarket] = useState<string | null>(null);
const refresh = useCallback(() => {
setTargets(loadVirtualTargets());
}, []);
useEffect(() => {
refresh();
const onChange = () => refresh();
window.addEventListener(VIRTUAL_SESSION_CHANGED_EVENT, onChange);
return () => window.removeEventListener(VIRTUAL_SESSION_CHANGED_EVENT, onChange);
}, [refresh]);
const addedSet = useMemo(
() => new Set(targets.map(t => t.market)),
[targets],
);
const isInTargets = useCallback(
(market: string) => addedSet.has(market),
[addedSet],
);
const isPinned = useCallback(
(market: string) => targets.find(t => t.market === market)?.pinned === true,
[targets],
);
const add = useCallback(async (market: string, meta?: VirtualTargetMeta) => {
if (addedSet.has(market) || busyMarket === market) return;
const maxCount = getVirtualTargetMaxCount();
if (targets.length >= maxCount) {
window.alert(virtualTargetLimitMessage(maxCount));
return;
}
setBusyMarket(market);
try {
const next = await addVirtualTarget(market, meta);
setTargets(next);
} catch (e) {
console.warn('[VirtualTarget] add failed', market, e);
window.alert('투자대상 추가에 실패했습니다.');
} finally {
setBusyMarket(null);
}
}, [addedSet, busyMarket, targets]);
const remove = useCallback(async (market: string) => {
if (!addedSet.has(market) || busyMarket === market) return;
setBusyMarket(market);
try {
const next = await removeVirtualTarget(market);
setTargets(next);
} catch (e) {
console.warn('[VirtualTarget] remove failed', market, e);
window.alert('투자대상 제거에 실패했습니다.');
} finally {
setBusyMarket(null);
}
}, [addedSet, busyMarket, targets]);
return {
addedSet,
isInTargets,
isPinned,
add,
remove,
busyMarket,
};
}