diff --git a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/helpers/contentHelpers.ts b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/helpers/contentHelpers.ts index 1159d310..857aeaf7 100644 --- a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/helpers/contentHelpers.ts +++ b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/helpers/contentHelpers.ts @@ -55,6 +55,22 @@ export function schedulePendingAdditionForSig( ); } +export function mergeLocalPendingAdditions( + serverSigs: ExtendedSystemSignature[], + localSigs: ExtendedSystemSignature[], +): ExtendedSystemSignature[] { + const now = Date.now(); + const pendingAdditions = localSigs.filter(sig => sig.pendingAddition && sig.pendingUntil && sig.pendingUntil > now); + const mergedMap = new Map(); + serverSigs.forEach(sig => mergedMap.set(sig.eve_id, sig)); + pendingAdditions.forEach(sig => { + if (!mergedMap.has(sig.eve_id)) { + mergedMap.set(sig.eve_id, sig); + } + }); + return Array.from(mergedMap.values()); +} + export function scheduleLazyDeletionTimers( toRemove: ExtendedSystemSignature[], setPendingMap: React.Dispatch>>, diff --git a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/types.ts b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/types.ts index d215125b..8c4ca3da 100644 --- a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/types.ts +++ b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/types.ts @@ -1,10 +1,5 @@ -// types.ts import { ExtendedSystemSignature } from '../helpers/contentHelpers'; -import { OutCommandHandler } from '@/hooks/Mapper/types/mapHandlers'; // or your function type -/** - * The aggregator’s props - */ export interface UseSystemSignaturesDataProps { systemId: string; settings: { key: string; value: boolean }[]; @@ -14,9 +9,6 @@ export interface UseSystemSignaturesDataProps { onLazyDeleteChange?: (value: boolean) => void; } -/** - * The minimal fetch logic - */ export interface UseFetchingParams { systemId: string; signaturesRef: React.MutableRefObject; @@ -24,17 +16,11 @@ export interface UseFetchingParams { localPendingDeletions: ExtendedSystemSignature[]; } -/** - * For the deletion sub-hook - */ export interface UsePendingDeletionParams { systemId: string; setSignatures: React.Dispatch>; } -/** - * For the additions sub-hook - */ export interface UsePendingAdditionParams { setSignatures: React.Dispatch>; } diff --git a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/usePendingAdditions.ts b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/usePendingAdditions.ts index abaa3bb3..dbba5def 100644 --- a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/usePendingAdditions.ts +++ b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/usePendingAdditions.ts @@ -5,12 +5,20 @@ import { FINAL_DURATION_MS } from '../constants'; export function usePendingAdditions({ setSignatures }: UsePendingAdditionParams) { const [pendingUndoAdditions, setPendingUndoAdditions] = useState([]); - const pendingAdditionMapRef = useRef>({}); const processAddedSignatures = useCallback( (added: ExtendedSystemSignature[]) => { if (!added.length) return; + const now = Date.now(); + setSignatures(prev => [ + ...prev, + ...added.map(sig => ({ + ...sig, + pendingAddition: true, + pendingUntil: now + FINAL_DURATION_MS, + })), + ]); added.forEach(sig => { schedulePendingAdditionForSig( sig, @@ -29,7 +37,6 @@ export function usePendingAdditions({ setSignatures }: UsePendingAdditionParams) clearTimeout(finalTimeoutId); }); pendingAdditionMapRef.current = {}; - setSignatures(prev => prev.map(x => (x.pendingAddition ? { ...x, pendingAddition: false, pendingUntil: undefined } : x)), ); diff --git a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/usePendingDeletions.ts b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/usePendingDeletions.ts index f08a29c6..aeafcb58 100644 --- a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/usePendingDeletions.ts +++ b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/usePendingDeletions.ts @@ -19,14 +19,28 @@ export function usePendingDeletions({ systemId, setSignatures }: UsePendingDelet updated: ExtendedSystemSignature[], ) => { if (!removed.length) return; - const processedRemoved = removed.map(r => ({ ...r, pendingDeletion: true, pendingAddition: false })); + const now = Date.now(); + const processedRemoved = removed.map(r => ({ + ...r, + pendingDeletion: true, + pendingAddition: false, + pendingUntil: now + FINAL_DURATION_MS, + })); setLocalPendingDeletions(prev => [...prev, ...processedRemoved]); - const resp = await outCommand({ + outCommand({ type: OutCommand.updateSignatures, data: prepareUpdatePayload(systemId, added, updated, []), }); - const updatedFromServer = resp.signatures as ExtendedSystemSignature[]; + + setSignatures(prev => + prev.map(sig => { + if (processedRemoved.find(r => r.eve_id === sig.eve_id)) { + return { ...sig, pendingDeletion: true, pendingUntil: now + FINAL_DURATION_MS }; + } + return sig; + }), + ); scheduleLazyDeletionTimers( processedRemoved, @@ -41,18 +55,6 @@ export function usePendingDeletions({ systemId, setSignatures }: UsePendingDelet }, FINAL_DURATION_MS, ); - - const now = Date.now(); - const updatedWithRemoval = updatedFromServer.map(sig => { - const wasRemoved = processedRemoved.find(r => r.eve_id === sig.eve_id); - return wasRemoved ? { ...sig, pendingDeletion: true, pendingUntil: now + FINAL_DURATION_MS } : sig; - }); - - const extras = processedRemoved - .map(r => ({ ...r, pendingDeletion: true, pendingUntil: now + FINAL_DURATION_MS })) - .filter(r => !updatedWithRemoval.some(m => m.eve_id === r.eve_id)); - - setSignatures([...updatedWithRemoval, ...extras]); }, [systemId, outCommand, setSignatures], ); @@ -60,7 +62,6 @@ export function usePendingDeletions({ systemId, setSignatures }: UsePendingDelet const clearPendingDeletions = useCallback(() => { Object.values(pendingDeletionMap).forEach(({ finalTimeoutId }) => clearTimeout(finalTimeoutId)); setPendingDeletionMap({}); - setSignatures(prev => prev.map(x => (x.pendingDeletion ? { ...x, pendingDeletion: false, pendingUntil: undefined } : x)), ); @@ -72,7 +73,6 @@ export function usePendingDeletions({ systemId, setSignatures }: UsePendingDelet setLocalPendingDeletions, pendingDeletionMap, setPendingDeletionMap, - processRemovedSignatures, clearPendingDeletions, }; diff --git a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/useSignatureFetching.ts b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/useSignatureFetching.ts index 67e3bb04..740cc488 100644 --- a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/useSignatureFetching.ts +++ b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/useSignatureFetching.ts @@ -1,8 +1,9 @@ import { useCallback } from 'react'; import { SystemSignature } from '@/hooks/Mapper/types'; import { OutCommand } from '@/hooks/Mapper/types/mapHandlers'; -import { ExtendedSystemSignature, prepareUpdatePayload, getActualSigs } from '../helpers'; +import { ExtendedSystemSignature, prepareUpdatePayload, getActualSigs, mergeLocalPendingAdditions } from '../helpers'; import { UseFetchingParams } from './types'; +import { FINAL_DURATION_MS } from '../constants'; import { useMapRootState } from '@/hooks/Mapper/mapRootProvider'; export function useSignatureFetching({ @@ -33,7 +34,7 @@ export function useSignatureFetching({ ...s, character_name: characters.find(c => c.eve_id === s.character_eve_id)?.name, })) as ExtendedSystemSignature[]; - setSignatures(extended); + setSignatures(prev => mergeLocalPendingAdditions(extended, prev)); }, [characters, systemId, localPendingDeletions, outCommand, setSignatures]); const handleUpdateSignatures = useCallback( @@ -45,12 +46,24 @@ export function useSignatureFetching({ skipUpdateUntouched, ); + if (added.length > 0) { + const now = Date.now(); + setSignatures(prev => [ + ...prev, + ...added.map(a => ({ + ...a, + pendingAddition: true, + pendingUntil: now + FINAL_DURATION_MS, + })), + ]); + } + await outCommand({ type: OutCommand.updateSignatures, data: prepareUpdatePayload(systemId, added, updated, removed), }); }, - [systemId, signaturesRef, outCommand], + [systemId, outCommand, signaturesRef, setSignatures], ); return { diff --git a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/useSystemSignaturesData.ts b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/useSystemSignaturesData.ts index cab79aaf..20085fa5 100644 --- a/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/useSystemSignaturesData.ts +++ b/assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/hooks/useSystemSignaturesData.ts @@ -1,6 +1,5 @@ import { useCallback, useEffect, useState } from 'react'; import useRefState from 'react-usestateref'; -import { useMapRootState } from '@/hooks/Mapper/mapRootProvider'; import { useMapEventListener } from '@/hooks/Mapper/events'; import { Commands, SystemSignature } from '@/hooks/Mapper/types'; import { OutCommand } from '@/hooks/Mapper/types/mapHandlers'; @@ -9,13 +8,14 @@ import { KEEP_LAZY_DELETE_SETTING, LAZY_DELETE_SIGNATURES_SETTING, } from '@/hooks/Mapper/components/mapInterface/widgets'; -import { ExtendedSystemSignature, getActualSigs } from '../helpers'; +import { ExtendedSystemSignature, getActualSigs, mergeLocalPendingAdditions } from '../helpers'; import { useSignatureFetching } from './useSignatureFetching'; import { usePendingAdditions } from './usePendingAdditions'; import { usePendingDeletions } from './usePendingDeletions'; import { UseSystemSignaturesDataProps } from './types'; import { TIME_ONE_DAY, TIME_ONE_WEEK } from '../constants'; import { SignatureGroup } from '@/hooks/Mapper/types'; +import { useMapRootState } from '@/hooks/Mapper/mapRootProvider'; export function useSystemSignaturesData({ systemId, @@ -25,9 +25,7 @@ export function useSystemSignaturesData({ onLazyDeleteChange, }: UseSystemSignaturesDataProps) { const { outCommand } = useMapRootState(); - const [signatures, setSignatures, signaturesRef] = useRefState([]); - const [selectedSignatures, setSelectedSignatures] = useState([]); const { localPendingDeletions, setLocalPendingDeletions, processRemovedSignatures, clearPendingDeletions } = @@ -51,7 +49,6 @@ export function useSystemSignaturesData({ const handlePaste = useCallback( async (clipboardString: string) => { const lazyDeleteValue = settings.find(s => s.key === LAZY_DELETE_SIGNATURES_SETTING)?.value ?? false; - const incomingSignatures = parseSignatures( clipboardString, settings.map(s => s.key), @@ -79,8 +76,15 @@ export function useSystemSignaturesData({ removed: [], }, }); - const finalSigs = (resp.signatures ?? []) as SystemSignature[]; - setSignatures(finalSigs.map(x => ({ ...x }))); + if (resp) { + const finalSigs = (resp.signatures ?? []) as SystemSignature[]; + setSignatures(prev => + mergeLocalPendingAdditions( + finalSigs.map(x => ({ ...x })), + prev, + ), + ); + } } const keepLazy = settings.find(s => s.key === KEEP_LAZY_DELETE_SETTING)?.value ?? false; @@ -115,16 +119,9 @@ export function useSystemSignaturesData({ const undoPending = useCallback(() => { clearPendingDeletions(); clearPendingAdditions(); - setSignatures(prev => - prev.map(x => { - if (x.pendingDeletion) { - return { ...x, pendingDeletion: false, pendingUntil: undefined }; - } - return x; - }), + prev.map(x => (x.pendingDeletion ? { ...x, pendingDeletion: false, pendingUntil: undefined } : x)), ); - if (pendingUndoAdditions.length) { pendingUndoAdditions.forEach(async sig => { await outCommand({ @@ -140,7 +137,6 @@ export function useSystemSignaturesData({ setSignatures(prev => prev.filter(x => !pendingUndoAdditions.some(u => u.eve_id === x.eve_id))); setPendingUndoAdditions([]); } - setLocalPendingDeletions([]); }, [ clearPendingDeletions,