diff --git a/assets/js/hooks/Mapper/components/contexts/ContextMenuSystem/useContextMenuSystemItems.tsx b/assets/js/hooks/Mapper/components/contexts/ContextMenuSystem/useContextMenuSystemItems.tsx index e3315325..c96d495d 100644 --- a/assets/js/hooks/Mapper/components/contexts/ContextMenuSystem/useContextMenuSystemItems.tsx +++ b/assets/js/hooks/Mapper/components/contexts/ContextMenuSystem/useContextMenuSystemItems.tsx @@ -118,7 +118,11 @@ export const useContextMenuSystemItems = ({ }); if (isShowPingBtn) { - return {!hasPing ? 'Ping: RALLY' : 'Cancel: RALLY'}; + return ( + + {!hasPing ? 'Ping: RALLY' : 'Cancel: RALLY'} + + ); } return ( @@ -126,7 +130,7 @@ export const useContextMenuSystemItems = ({ infoTitle="Locked. Ping can be set only for one system." infoClass="pi-lock text-stone-500 mr-[12px]" > - + {!hasPing ? 'Ping: RALLY' : 'Cancel: RALLY'} diff --git a/assets/js/hooks/Mapper/components/contexts/ContextMenuSystemMultiple/ContextMenuSystemMultiple.tsx b/assets/js/hooks/Mapper/components/contexts/ContextMenuSystemMultiple/ContextMenuSystemMultiple.tsx index a319b449..690092a4 100644 --- a/assets/js/hooks/Mapper/components/contexts/ContextMenuSystemMultiple/ContextMenuSystemMultiple.tsx +++ b/assets/js/hooks/Mapper/components/contexts/ContextMenuSystemMultiple/ContextMenuSystemMultiple.tsx @@ -2,6 +2,10 @@ import React, { RefObject, useMemo } from 'react'; import { ContextMenu } from 'primereact/contextmenu'; import { PrimeIcons } from 'primereact/api'; import { MenuItem } from 'primereact/menuitem'; +import { checkPermissions } from '@/hooks/Mapper/components/map/helpers'; +import { useMapRootState } from '@/hooks/Mapper/mapRootProvider'; +import { MenuItemWithInfo, WdMenuItem } from '@/hooks/Mapper/components/ui-kit'; +import clsx from 'clsx'; export interface ContextMenuSystemMultipleProps { contextMenuRef: RefObject; @@ -14,20 +18,41 @@ export const ContextMenuSystemMultiple: React.FC onDeleteSystems, onCopySystems, }) => { + const { + data: { options, userPermissions }, + } = useMapRootState(); + const items: MenuItem[] = useMemo(() => { + const allowCopy = checkPermissions(userPermissions, options.allowed_copy_for); + return [ + { + label: 'Delete', + icon: clsx(PrimeIcons.TRASH, 'text-red-400'), + command: onDeleteSystems, + }, + { separator: true }, { label: 'Copy', icon: PrimeIcons.COPY, command: onCopySystems, - }, - { - label: 'Delete', - icon: PrimeIcons.TRASH, - command: onDeleteSystems, + disabled: !allowCopy, + template: () => { + return ( + + + Copy + + + ); + }, }, ]; - }, [onCopySystems, onDeleteSystems]); + }, [onCopySystems, onDeleteSystems, options, userPermissions]); return ( <> diff --git a/assets/js/hooks/Mapper/components/map/components/ContextMenuRoot/ContextMenuRoot.tsx b/assets/js/hooks/Mapper/components/map/components/ContextMenuRoot/ContextMenuRoot.tsx index f74d3fe5..5732bbde 100644 --- a/assets/js/hooks/Mapper/components/map/components/ContextMenuRoot/ContextMenuRoot.tsx +++ b/assets/js/hooks/Mapper/components/map/components/ContextMenuRoot/ContextMenuRoot.tsx @@ -3,6 +3,10 @@ import { ContextMenu } from 'primereact/contextmenu'; import { PrimeIcons } from 'primereact/api'; import { MenuItem } from 'primereact/menuitem'; import { PasteSystemsAndConnections } from '@/hooks/Mapper/components/map/components'; +import { useMapState } from '@/hooks/Mapper/components/map/MapProvider.tsx'; +import { checkPermissions } from '@/hooks/Mapper/components/map/helpers'; +import { MenuItemWithInfo, WdMenuItem } from '@/hooks/Mapper/components/ui-kit'; +import clsx from 'clsx'; export interface ContextMenuRootProps { contextMenuRef: RefObject; @@ -17,7 +21,13 @@ export const ContextMenuRoot: React.FC = ({ onPasteSystemsAnsConnections, pasteSystemsAndConnections, }) => { + const { + data: { options, userPermissions }, + } = useMapState(); + const items: MenuItem[] = useMemo(() => { + const allowPaste = checkPermissions(userPermissions, options.allowed_paste_for); + return [ { label: 'Add System', @@ -27,14 +37,27 @@ export const ContextMenuRoot: React.FC = ({ ...(pasteSystemsAndConnections != null ? [ { - label: 'Paste', icon: 'pi pi-clipboard', + disabled: !allowPaste, command: onPasteSystemsAnsConnections, + template: () => { + return ( + + + Paste + + + ); + }, }, ] : []), ]; - }, [onAddSystem, onPasteSystemsAnsConnections, pasteSystemsAndConnections]); + }, [userPermissions, options, onAddSystem, pasteSystemsAndConnections, onPasteSystemsAnsConnections]); return ( <> diff --git a/assets/js/hooks/Mapper/components/map/helpers/checkPermissions.ts b/assets/js/hooks/Mapper/components/map/helpers/checkPermissions.ts new file mode 100644 index 00000000..27067353 --- /dev/null +++ b/assets/js/hooks/Mapper/components/map/helpers/checkPermissions.ts @@ -0,0 +1,5 @@ +import { UserPermission, UserPermissions } from '@/hooks/Mapper/types'; + +export const checkPermissions = (permissions: Partial, targetPermission: UserPermission) => { + return targetPermission != null && permissions[targetPermission]; +}; diff --git a/assets/js/hooks/Mapper/components/map/helpers/index.ts b/assets/js/hooks/Mapper/components/map/helpers/index.ts index a13d842a..e0842a4f 100644 --- a/assets/js/hooks/Mapper/components/map/helpers/index.ts +++ b/assets/js/hooks/Mapper/components/map/helpers/index.ts @@ -4,3 +4,4 @@ export * from './getSystemClassStyles'; export * from './getShapeClass'; export * from './getBackgroundClass'; export * from './prepareUnsplashedChunks'; +export * from './checkPermissions'; diff --git a/assets/js/hooks/Mapper/components/map/hooks/api/useMapInit.ts b/assets/js/hooks/Mapper/components/map/hooks/api/useMapInit.ts index 2b739772..912268ac 100644 --- a/assets/js/hooks/Mapper/components/map/hooks/api/useMapInit.ts +++ b/assets/js/hooks/Mapper/components/map/hooks/api/useMapInit.ts @@ -38,6 +38,8 @@ export const useMapInit = () => { user_characters, present_characters, hubs, + options, + user_permissions, }: CommandInit) => { const { update } = ref.current; @@ -63,6 +65,14 @@ export const useMapInit = () => { updateData.hubs = hubs; } + if (options) { + updateData.options = options; + } + + if (options) { + updateData.userPermissions = user_permissions; + } + if (systems) { updateData.systems = systems; } diff --git a/assets/js/hooks/Mapper/components/map/hooks/useMapHandlers.ts b/assets/js/hooks/Mapper/components/map/hooks/useMapHandlers.ts index bd0068c3..11f594cf 100644 --- a/assets/js/hooks/Mapper/components/map/hooks/useMapHandlers.ts +++ b/assets/js/hooks/Mapper/components/map/hooks/useMapHandlers.ts @@ -49,87 +49,91 @@ export const useMapHandlers = (ref: ForwardedRef, onSelectionChange const { charactersUpdated, presentCharacters, characterAdded, characterRemoved, characterUpdated } = useCommandsCharacters(); - useImperativeHandle(ref, () => { - return { - command(type, data) { - switch (type) { - case Commands.init: - mapInit(data as CommandInit); - break; - case Commands.addSystems: - setTimeout(() => mapAddSystems(data as CommandAddSystems), 100); - break; - case Commands.updateSystems: - mapUpdateSystems(data as CommandUpdateSystems); - break; - case Commands.removeSystems: - setTimeout(() => removeSystems(data as CommandRemoveSystems), 100); - break; - case Commands.addConnections: - setTimeout(() => addConnections(data as CommandAddConnections), 100); - break; - case Commands.removeConnections: - setTimeout(() => removeConnections(data as CommandRemoveConnections), 100); - break; - case Commands.charactersUpdated: - charactersUpdated(data as CommandCharactersUpdated); - break; - case Commands.characterAdded: - characterAdded(data as CommandCharacterAdded); - break; - case Commands.characterRemoved: - characterRemoved(data as CommandCharacterRemoved); - break; - case Commands.characterUpdated: - characterUpdated(data as CommandCharacterUpdated); - break; - case Commands.presentCharacters: - presentCharacters(data as CommandPresentCharacters); - break; - case Commands.updateConnection: - updateConnection(data as CommandUpdateConnection); - break; - case Commands.mapUpdated: - mapUpdated(data as CommandMapUpdated); - break; - case Commands.killsUpdated: - killsUpdated(data as CommandKillsUpdated); - break; + useImperativeHandle( + ref, + () => { + return { + command(type, data) { + switch (type) { + case Commands.init: + mapInit(data as CommandInit); + break; + case Commands.addSystems: + setTimeout(() => mapAddSystems(data as CommandAddSystems), 100); + break; + case Commands.updateSystems: + mapUpdateSystems(data as CommandUpdateSystems); + break; + case Commands.removeSystems: + setTimeout(() => removeSystems(data as CommandRemoveSystems), 100); + break; + case Commands.addConnections: + setTimeout(() => addConnections(data as CommandAddConnections), 100); + break; + case Commands.removeConnections: + setTimeout(() => removeConnections(data as CommandRemoveConnections), 100); + break; + case Commands.charactersUpdated: + charactersUpdated(data as CommandCharactersUpdated); + break; + case Commands.characterAdded: + characterAdded(data as CommandCharacterAdded); + break; + case Commands.characterRemoved: + characterRemoved(data as CommandCharacterRemoved); + break; + case Commands.characterUpdated: + characterUpdated(data as CommandCharacterUpdated); + break; + case Commands.presentCharacters: + presentCharacters(data as CommandPresentCharacters); + break; + case Commands.updateConnection: + updateConnection(data as CommandUpdateConnection); + break; + case Commands.mapUpdated: + mapUpdated(data as CommandMapUpdated); + break; + case Commands.killsUpdated: + killsUpdated(data as CommandKillsUpdated); + break; - case Commands.centerSystem: - setTimeout(() => { - const systemId = `${data}`; - centerSystem(systemId as CommandSelectSystem); - }, 100); - break; + case Commands.centerSystem: + setTimeout(() => { + const systemId = `${data}`; + centerSystem(systemId as CommandSelectSystem); + }, 100); + break; - case Commands.selectSystem: - selectSystems({ systems: [data as string], delay: 500 }); - break; + case Commands.selectSystem: + selectSystems({ systems: [data as string], delay: 500 }); + break; - case Commands.selectSystems: - selectSystems(data as CommandSelectSystems); - break; + case Commands.selectSystems: + selectSystems(data as CommandSelectSystems); + break; - case Commands.pingAdded: - case Commands.pingCancelled: - case Commands.routes: - case Commands.signaturesUpdated: - case Commands.linkSignatureToSystem: - case Commands.detailedKillsUpdated: - case Commands.characterActivityData: - case Commands.trackingCharactersData: - case Commands.updateActivity: - case Commands.updateTracking: - case Commands.userSettingsUpdated: - // do nothing - break; + case Commands.pingAdded: + case Commands.pingCancelled: + case Commands.routes: + case Commands.signaturesUpdated: + case Commands.linkSignatureToSystem: + case Commands.detailedKillsUpdated: + case Commands.characterActivityData: + case Commands.trackingCharactersData: + case Commands.updateActivity: + case Commands.updateTracking: + case Commands.userSettingsUpdated: + // do nothing + break; - default: - console.warn(`Map handlers: Unknown command: ${type}`, data); - break; - } - }, - }; - }, []); + default: + console.warn(`Map handlers: Unknown command: ${type}`, data); + break; + } + }, + }; + }, + [], + ); }; diff --git a/assets/js/hooks/Mapper/components/ui-kit/MenuItemWithInfo.tsx b/assets/js/hooks/Mapper/components/ui-kit/MenuItemWithInfo.tsx index 9c7a295b..675eb64e 100644 --- a/assets/js/hooks/Mapper/components/ui-kit/MenuItemWithInfo.tsx +++ b/assets/js/hooks/Mapper/components/ui-kit/MenuItemWithInfo.tsx @@ -4,8 +4,17 @@ import { WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrap import { TooltipPosition } from '@/hooks/Mapper/components/ui-kit/WdTooltip'; import clsx from 'clsx'; -type MenuItemWithInfoProps = { infoTitle: ReactNode; infoClass?: string } & WithChildren; -export const MenuItemWithInfo = ({ children, infoClass, infoTitle }: MenuItemWithInfoProps) => { +type MenuItemWithInfoProps = { + infoTitle: ReactNode; + infoClass?: string; + tooltipWrapperClassName?: string; +} & WithChildren; +export const MenuItemWithInfo = ({ + children, + infoClass, + infoTitle, + tooltipWrapperClassName, +}: MenuItemWithInfoProps) => { return (
{children} @@ -13,6 +22,7 @@ export const MenuItemWithInfo = ({ children, infoClass, infoTitle }: MenuItemWit content={infoTitle} position={TooltipPosition.top} className="!opacity-100 !pointer-events-auto" + wrapperClassName={tooltipWrapperClassName} >
diff --git a/assets/js/hooks/Mapper/components/ui-kit/WdMenuItem.tsx b/assets/js/hooks/Mapper/components/ui-kit/WdMenuItem.tsx index 3af102d2..014662d3 100644 --- a/assets/js/hooks/Mapper/components/ui-kit/WdMenuItem.tsx +++ b/assets/js/hooks/Mapper/components/ui-kit/WdMenuItem.tsx @@ -1,13 +1,18 @@ -import { WithChildren } from '@/hooks/Mapper/types/common.ts'; +import { WithChildren, WithClassName } from '@/hooks/Mapper/types/common.ts'; import clsx from 'clsx'; -type WdMenuItemProps = { icon?: string; disabled?: boolean } & WithChildren; -export const WdMenuItem = ({ children, icon, disabled }: WdMenuItemProps) => { +type WdMenuItemProps = { icon?: string; disabled?: boolean } & WithChildren & WithClassName; +export const WdMenuItem = ({ children, icon, disabled, className }: WdMenuItemProps) => { return ( {icon &&
}
{children}
diff --git a/assets/js/hooks/Mapper/components/ui-kit/WdTooltipWrapper/WdTooltipWrapper.tsx b/assets/js/hooks/Mapper/components/ui-kit/WdTooltipWrapper/WdTooltipWrapper.tsx index ce5d80ce..5090a4f4 100644 --- a/assets/js/hooks/Mapper/components/ui-kit/WdTooltipWrapper/WdTooltipWrapper.tsx +++ b/assets/js/hooks/Mapper/components/ui-kit/WdTooltipWrapper/WdTooltipWrapper.tsx @@ -10,6 +10,7 @@ export type WdTooltipWrapperProps = { interactive?: boolean; smallPaddings?: boolean; tooltipClassName?: string; + wrapperClassName?: string; } & Omit, 'content' | 'size'> & Omit; @@ -26,6 +27,7 @@ export const WdTooltipWrapper = forwardRef - {targetSelector ? <>{children} :
{children}
} + {targetSelector ? <>{children} :
{children}
} = { [Spaces.Gallente]: 'Gallente', [Spaces.Pochven]: 'Pochven', }; + +export const PERMISSIONS_POWER_MAP = { + [UserPermission.ADD_SYSTEM]: [UserPermission.ADD_SYSTEM, UserPermission.MANAGE_MAP, UserPermission.ADMIN_MAP], + [UserPermission.MANAGE_MAP]: [UserPermission.MANAGE_MAP, UserPermission.ADMIN_MAP], + [UserPermission.ADMIN_MAP]: [UserPermission.ADMIN_MAP], +}; diff --git a/assets/js/hooks/Mapper/types/index.ts b/assets/js/hooks/Mapper/types/index.ts index 1343e17c..142ef976 100644 --- a/assets/js/hooks/Mapper/types/index.ts +++ b/assets/js/hooks/Mapper/types/index.ts @@ -9,3 +9,4 @@ export * from './connectionPassages'; export * from './permissions'; export * from './comment'; export * from './ping'; +export * from './options'; diff --git a/assets/js/hooks/Mapper/types/mapHandlers.ts b/assets/js/hooks/Mapper/types/mapHandlers.ts index e7b9c805..aaae0ff5 100644 --- a/assets/js/hooks/Mapper/types/mapHandlers.ts +++ b/assets/js/hooks/Mapper/types/mapHandlers.ts @@ -1,4 +1,4 @@ -import { CommentType, PingData, SystemSignature, UserPermissions } from '@/hooks/Mapper/types'; +import { CommentType, MapOptions, PingData, SystemSignature, UserPermissions } from '@/hooks/Mapper/types'; import { ActivitySummary, CharacterTypeRaw, TrackingCharacter } from '@/hooks/Mapper/types/character.ts'; import { SolarSystemConnection } from '@/hooks/Mapper/types/connection.ts'; import { DetailedKill, Kill } from '@/hooks/Mapper/types/kills.ts'; @@ -94,7 +94,7 @@ export type CommandInit = { hubs: string[]; user_hubs: string[]; routes: RoutesList; - options: Record; + options: MapOptions; reset?: boolean; is_subscription_active?: boolean; main_character_eve_id?: string | null; diff --git a/assets/js/hooks/Mapper/types/mapUnionTypes.ts b/assets/js/hooks/Mapper/types/mapUnionTypes.ts index 31ae4099..d4230dc4 100644 --- a/assets/js/hooks/Mapper/types/mapUnionTypes.ts +++ b/assets/js/hooks/Mapper/types/mapUnionTypes.ts @@ -4,7 +4,7 @@ import { CharacterTypeRaw } from '@/hooks/Mapper/types/character.ts'; import { SolarSystemRawType } from '@/hooks/Mapper/types/system.ts'; import { RoutesList } from '@/hooks/Mapper/types/routes.ts'; import { SolarSystemConnection } from '@/hooks/Mapper/types/connection.ts'; -import { PingData, UserPermissions } from '@/hooks/Mapper/types'; +import { MapOptions, PingData, UserPermissions } from '@/hooks/Mapper/types'; import { SystemSignature } from '@/hooks/Mapper/types/signatures'; export type MapUnionTypes = { @@ -23,7 +23,7 @@ export type MapUnionTypes = { kills: Record; connections: SolarSystemConnection[]; userPermissions: Partial; - options: Record; + options: MapOptions; isSubscriptionActive: boolean; mainCharacterEveId: string | null; diff --git a/assets/js/hooks/Mapper/types/options.ts b/assets/js/hooks/Mapper/types/options.ts new file mode 100644 index 00000000..5b6f0017 --- /dev/null +++ b/assets/js/hooks/Mapper/types/options.ts @@ -0,0 +1,14 @@ +import { UserPermission } from '@/hooks/Mapper/types/permissions.ts'; + +export type StringBoolean = 'true' | 'false'; + +export type MapOptions = { + allowed_copy_for: UserPermission; + allowed_paste_for: UserPermission; + layout: string; + restrict_offline_showing: StringBoolean; + show_linked_signature_id: StringBoolean; + show_linked_signature_id_temp_name: StringBoolean; + show_temp_system_name: StringBoolean; + store_custom_labels: StringBoolean; +};