diff --git a/assets/js/hooks/Mapper/components/contexts/ContextMenuSystemInfo/ContextMenuSystemInfo.tsx b/assets/js/hooks/Mapper/components/contexts/ContextMenuSystemInfo/ContextMenuSystemInfo.tsx index e379c98f..ce6b3cc8 100644 --- a/assets/js/hooks/Mapper/components/contexts/ContextMenuSystemInfo/ContextMenuSystemInfo.tsx +++ b/assets/js/hooks/Mapper/components/contexts/ContextMenuSystemInfo/ContextMenuSystemInfo.tsx @@ -8,17 +8,21 @@ import { getSystemById } from '@/hooks/Mapper/helpers'; import { useWaypointMenu } from '@/hooks/Mapper/components/contexts/hooks'; import { WaypointSetContextHandler } from '@/hooks/Mapper/components/contexts/types.ts'; import { FastSystemActions } from '@/hooks/Mapper/components/contexts/components'; +import { useJumpPlannerMenu } from '@/hooks/Mapper/components/contexts/hooks/useJumpPlannerMenu'; +import { Route } from '@/hooks/Mapper/types/routes.ts'; export interface ContextMenuSystemInfoProps { systemStatics: Map; hubs: string[]; contextMenuRef: RefObject; systemId: string | undefined; + systemIdFrom?: string | undefined; systems: SolarSystemRawType[]; onOpenSettings(): void; onHubToggle(): void; onAddSystem(): void; onWaypointSet: WaypointSetContextHandler; + routes: Route[]; } export const ContextMenuSystemInfo: React.FC = ({ @@ -30,9 +34,12 @@ export const ContextMenuSystemInfo: React.FC = ({ onAddSystem, onWaypointSet, systemId, + systemIdFrom, hubs, + routes, }) => { const getWaypointMenu = useWaypointMenu(onWaypointSet); + const getJumpPlannerMenu = useJumpPlannerMenu(systems, systemIdFrom); const items: MenuItem[] = useMemo(() => { const system = systemId ? systemStatics.get(parseInt(systemId)) : undefined; @@ -55,7 +62,9 @@ export const ContextMenuSystemInfo: React.FC = ({ ); }, }, + { separator: true }, + ...getJumpPlannerMenu(system, routes), ...getWaypointMenu(systemId, system.system_class), { label: !hubs.includes(systemId) ? 'Add in Routes' : 'Remove from Routes', @@ -72,7 +81,17 @@ export const ContextMenuSystemInfo: React.FC = ({ ] : []), ]; - }, [systemId, systemStatics, systems, getWaypointMenu, hubs, onHubToggle, onAddSystem, onOpenSettings]); + }, [ + systemId, + systemStatics, + systems, + getJumpPlannerMenu, + getWaypointMenu, + hubs, + onHubToggle, + onAddSystem, + onOpenSettings, + ]); return ( <> diff --git a/assets/js/hooks/Mapper/components/contexts/ContextMenuSystemInfo/useContextMenuSystemInfoHandlers.ts b/assets/js/hooks/Mapper/components/contexts/ContextMenuSystemInfo/useContextMenuSystemInfoHandlers.ts index 44c142f2..3a11edb1 100644 --- a/assets/js/hooks/Mapper/components/contexts/ContextMenuSystemInfo/useContextMenuSystemInfoHandlers.ts +++ b/assets/js/hooks/Mapper/components/contexts/ContextMenuSystemInfo/useContextMenuSystemInfoHandlers.ts @@ -4,6 +4,7 @@ import { Commands, MapHandlers, OutCommand, OutCommandHandler } from '@/hooks/Ma import { WaypointSetContextHandler } from '@/hooks/Mapper/components/contexts/types.ts'; import { ctxManager } from '@/hooks/Mapper/utils/contextManager.ts'; import * as React from 'react'; +import { SolarSystemStaticInfoRaw } from '@/hooks/Mapper/types'; interface UseContextMenuSystemHandlersProps { hubs: string[]; @@ -15,16 +16,21 @@ export const useContextMenuSystemInfoHandlers = ({ hubs, outCommand, mapRef }: U const contextMenuRef = useRef(null); const [system, setSystem] = useState(); + const routeRef = useRef<(SolarSystemStaticInfoRaw | undefined)[]>([]); const ref = useRef({ hubs, system, outCommand, mapRef }); ref.current = { hubs, system, outCommand, mapRef }; - const open = useCallback((ev: React.SyntheticEvent, systemId: string) => { - setSystem(systemId); - ev.preventDefault(); - ctxManager.next('ctxSysInfo', contextMenuRef.current); - contextMenuRef.current?.show(ev); - }, []); + const open = useCallback( + (ev: React.SyntheticEvent, systemId: string, route: (SolarSystemStaticInfoRaw | undefined)[]) => { + setSystem(systemId); + routeRef.current = route; + ev.preventDefault(); + ctxManager.next('ctxSysInfo', contextMenuRef.current); + contextMenuRef.current?.show(ev); + }, + [], + ); const onHubToggle = useCallback(() => { const { hubs, system, outCommand } = ref.current; diff --git a/assets/js/hooks/Mapper/components/contexts/hooks/useJumpPlannerMenu/index.ts b/assets/js/hooks/Mapper/components/contexts/hooks/useJumpPlannerMenu/index.ts new file mode 100644 index 00000000..a0a26604 --- /dev/null +++ b/assets/js/hooks/Mapper/components/contexts/hooks/useJumpPlannerMenu/index.ts @@ -0,0 +1 @@ +export * from './useJumpPlannerMenu.tsx'; diff --git a/assets/js/hooks/Mapper/components/contexts/hooks/useJumpPlannerMenu/useJumpPlannerMenu.tsx b/assets/js/hooks/Mapper/components/contexts/hooks/useJumpPlannerMenu/useJumpPlannerMenu.tsx new file mode 100644 index 00000000..e591dfc5 --- /dev/null +++ b/assets/js/hooks/Mapper/components/contexts/hooks/useJumpPlannerMenu/useJumpPlannerMenu.tsx @@ -0,0 +1,129 @@ +import { MenuItem } from 'primereact/menuitem'; +import { PrimeIcons } from 'primereact/api'; +import { useCallback } from 'react'; +import { isPossibleSpace } from '@/hooks/Mapper/components/map/helpers/isKnownSpace.ts'; +import { Route } from '@/hooks/Mapper/types/routes.ts'; +import { SolarSystemRawType, SolarSystemStaticInfoRaw } from '@/hooks/Mapper/types'; +import { getSystemById } from '@/hooks/Mapper/helpers'; +import { SOLAR_SYSTEM_CLASS_IDS } from '@/hooks/Mapper/components/map/constants.ts'; + +const imperialSpace = [SOLAR_SYSTEM_CLASS_IDS.hs, SOLAR_SYSTEM_CLASS_IDS.ls, SOLAR_SYSTEM_CLASS_IDS.ns]; +const criminalSpace = [SOLAR_SYSTEM_CLASS_IDS.ls, SOLAR_SYSTEM_CLASS_IDS.ns]; + +enum JUMP_SHIP_TYPE { + BLACK_OPS = 'Marshal', + JUMP_FREIGHTER = 'Anshar', + RORQUAL = 'Rorqual', + CAPITAL = 'Thanatos', + SUPER_CAPITAL = 'Avatar', +} + +export const openJumpPlan = (jumpShipType: JUMP_SHIP_TYPE, from: string, to: string) => { + return window.open(`https://evemaps.dotlan.net/jump/${jumpShipType},544/${from}:${to}`, '_blank'); +}; + +const BRACKET_ICONS = { + npcsuperCarrier_32: '/icons/brackets/npcsuperCarrier_32.png', + carrier_32: '/icons/brackets/carrier_32.png', + battleship_32: '/icons/brackets/battleship_32.png', + freighter_32: '/icons/brackets/freighter_32.png', +}; + +const renderIcon = (icon: string) => { + return ( +
+ +
+ ); +}; + +export const useJumpPlannerMenu = ( + systems: SolarSystemRawType[], + systemIdFrom?: string | undefined, +): ((systemId: SolarSystemStaticInfoRaw, routes: Route[]) => MenuItem[]) => { + return useCallback( + (destination: SolarSystemStaticInfoRaw) => { + if (!destination || !systemIdFrom) { + return []; + } + + const origin = getSystemById(systems, systemIdFrom)?.system_static_info; + + if (!origin) { + return []; + } + + const isShowBOorJumpFreighter = + isPossibleSpace(imperialSpace, origin.system_class) && isPossibleSpace(criminalSpace, destination.system_class); + + const isShowCapital = + isPossibleSpace(criminalSpace, origin.system_class) && isPossibleSpace(criminalSpace, destination.system_class); + + if (!isShowBOorJumpFreighter && !isShowCapital) { + return []; + } + + return [ + { + label: 'In Jump Planner', + icon: PrimeIcons.SEND, + items: [ + ...(isShowBOorJumpFreighter + ? [ + { + label: 'Black Ops', + icon: renderIcon(BRACKET_ICONS.battleship_32), + command: () => { + openJumpPlan(JUMP_SHIP_TYPE.BLACK_OPS, origin.solar_system_name, destination.solar_system_name); + }, + }, + { + label: 'Jump Freighter', + icon: renderIcon(BRACKET_ICONS.freighter_32), + command: () => { + openJumpPlan( + JUMP_SHIP_TYPE.JUMP_FREIGHTER, + origin.solar_system_name, + destination.solar_system_name, + ); + }, + }, + { + label: 'Rorqual', + icon: renderIcon(BRACKET_ICONS.freighter_32), + command: () => { + openJumpPlan(JUMP_SHIP_TYPE.RORQUAL, origin.solar_system_name, destination.solar_system_name); + }, + }, + ] + : []), + + ...(isShowCapital + ? [ + { + label: 'Capital', + icon: renderIcon(BRACKET_ICONS.carrier_32), + command: () => { + openJumpPlan(JUMP_SHIP_TYPE.CAPITAL, origin.solar_system_name, destination.solar_system_name); + }, + }, + { + label: 'Super Capital', + icon: renderIcon(BRACKET_ICONS.npcsuperCarrier_32), + command: () => { + openJumpPlan( + JUMP_SHIP_TYPE.SUPER_CAPITAL, + origin.solar_system_name, + destination.solar_system_name, + ); + }, + }, + ] + : []), + ], + }, + ]; + }, + [systems, systemIdFrom], + ); +}; diff --git a/assets/js/hooks/Mapper/components/map/helpers/isKnownSpace.ts b/assets/js/hooks/Mapper/components/map/helpers/isKnownSpace.ts index 38103994..7fa0b10c 100644 --- a/assets/js/hooks/Mapper/components/map/helpers/isKnownSpace.ts +++ b/assets/js/hooks/Mapper/components/map/helpers/isKnownSpace.ts @@ -11,3 +11,7 @@ export const isKnownSpace = (wormholeClassID: number) => { return false; }; + +export const isPossibleSpace = (spaces: number[], wormholeClassID: number) => { + return spaces.includes(wormholeClassID); +}; diff --git a/assets/js/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/RoutesWidget.tsx b/assets/js/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/RoutesWidget.tsx index b154ae82..7559e10d 100644 --- a/assets/js/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/RoutesWidget.tsx +++ b/assets/js/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/RoutesWidget.tsx @@ -54,7 +54,7 @@ export const RoutesWidgetContent = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [hubs, systems, systemStatics, lastUpdateKey]); - const preparedRoutes = useMemo(() => { + const preparedRoutes: Route[] = useMemo(() => { return ( routes?.routes .sort(sortByDist) @@ -71,15 +71,17 @@ export const RoutesWidgetContent = () => { ); }, [routes?.routes, routes?.systems_static_data, systemId]); - const refData = useRef({ open, loadSystems }); - refData.current = { open, loadSystems }; + const refData = useRef({ open, loadSystems, preparedRoutes }); + refData.current = { open, loadSystems, preparedRoutes }; useEffect(() => { (async () => await refData.current.loadSystems(hubs))(); }, [hubs]); const handleClick = useCallback((e: MouseEvent, systemId: string) => { - refData.current.open(e, systemId); + const route = refData.current.preparedRoutes.find(x => x.destination.toString() === systemId); + + refData.current.open(e, systemId, route?.mapped_systems ?? []); }, []); const handleContextMenu = useCallback( @@ -146,7 +148,14 @@ export const RoutesWidgetContent = () => { )} - + ); }; diff --git a/assets/static/icons/brackets/battleship_32.png b/assets/static/icons/brackets/battleship_32.png new file mode 100644 index 00000000..a7636819 Binary files /dev/null and b/assets/static/icons/brackets/battleship_32.png differ diff --git a/assets/static/icons/brackets/carrier_32.png b/assets/static/icons/brackets/carrier_32.png new file mode 100644 index 00000000..21729b21 Binary files /dev/null and b/assets/static/icons/brackets/carrier_32.png differ diff --git a/assets/static/icons/brackets/freighter_32.png b/assets/static/icons/brackets/freighter_32.png new file mode 100644 index 00000000..4e584553 Binary files /dev/null and b/assets/static/icons/brackets/freighter_32.png differ diff --git a/assets/static/icons/brackets/npcsuperCarrier_32.png b/assets/static/icons/brackets/npcsuperCarrier_32.png new file mode 100644 index 00000000..cfd622f5 Binary files /dev/null and b/assets/static/icons/brackets/npcsuperCarrier_32.png differ