diff --git a/src/components/map/Map.tsx b/src/components/map/Map.tsx index eb5f684..553f2f0 100644 --- a/src/components/map/Map.tsx +++ b/src/components/map/Map.tsx @@ -13,6 +13,7 @@ import NetworkedMapPointer from "../../network/NetworkedMapPointer"; import SelectTool from "../tools/SelectTool"; import { useSettings } from "../../contexts/SettingsContext"; +import { useUserId } from "../../contexts/UserIdContext"; import Action from "../../actions/Action"; import { @@ -41,10 +42,12 @@ import { import useMapTokens from "../../hooks/useMapTokens"; import useMapNotes from "../../hooks/useMapNotes"; +import { MapActions } from "../../hooks/useMapActions"; type MapProps = { map: MapType | null; mapState: MapState | null; + mapActions: MapActions; onMapTokenStateChange: TokenStateChangeEventHandler; onMapTokenStateRemove: TokenStateRemoveHandler; onMapChange: MapChangeEventHandler; @@ -54,11 +57,7 @@ type MapProps = { onMapNoteCreate: NoteCreateEventHander; onMapNoteChange: NoteChangeEventHandler; onMapNoteRemove: NoteRemoveEventHander; - allowMapDrawing: boolean; - allowFogDrawing: boolean; allowMapChange: boolean; - allowNoteEditing: boolean; - disabledTokens: Record; session: Session; onUndo: () => void; onRedo: () => void; @@ -67,6 +66,7 @@ type MapProps = { function Map({ map, mapState, + mapActions, onMapTokenStateChange, onMapTokenStateRemove, onMapChange, @@ -76,17 +76,15 @@ function Map({ onMapNoteCreate, onMapNoteChange, onMapNoteRemove, - allowMapDrawing, - allowFogDrawing, allowMapChange, - allowNoteEditing, - disabledTokens, session, onUndo, onRedo, }: MapProps) { const { addToast } = useToasts(); + const userId = useUserId(); + const [selectedToolId, setSelectedToolId] = useState("move"); const { settings, setSettings } = useSettings(); @@ -130,42 +128,12 @@ function Map({ onFogDraw(new EditStatesAction(shapes)); } - const disabledControls: MapToolId[] = []; - if (!allowMapDrawing) { - disabledControls.push("drawing"); - } - if (!map) { - disabledControls.push("move"); - disabledControls.push("measure"); - disabledControls.push("pointer"); - disabledControls.push("select"); - } - if (!allowFogDrawing) { - disabledControls.push("fog"); - } - if (!allowMapChange) { - disabledControls.push("map"); - } - if (!allowNoteEditing) { - disabledControls.push("note"); - } - - const disabledSettings: { - drawing: string[]; - } = { - drawing: [], - }; - if (drawShapes.length === 0) { - disabledSettings.drawing.push("erase"); - } - const { tokens, tokenMenu, tokenDragOverlay } = useMapTokens( map, mapState, onMapTokenStateChange, onMapTokenStateRemove, - selectedToolId, - disabledTokens + selectedToolId ); const { notes, noteMenu, noteDragOverlay } = useMapNotes( @@ -175,7 +143,7 @@ function Map({ onMapNoteChange, onMapNoteRemove, selectedToolId, - allowNoteEditing + !!(map?.owner === userId || mapState?.editFlags.includes("notes")) ); return ( @@ -188,15 +156,15 @@ function Map({ @@ -208,7 +176,6 @@ function Map({ } selectedToolId={selectedToolId} onSelectedToolChange={setSelectedToolId} - disabledControls={disabledControls} > {map && map.showGrid && } void; toolSettings: Settings; onToolSettingChange: (change: Partial) => void; onToolAction: (actionId: string) => void; - disabledControls: MapToolId[]; - disabledSettings: Partial>; onUndo: () => void; onRedo: () => void; }; @@ -58,21 +61,62 @@ type MapControlsProps = { function MapContols({ onMapChange, onMapReset, - currentMap, - currentMapState, + map, + mapState, + mapActions, + allowMapChange, selectedToolId, onSelectedToolChange, toolSettings, onToolSettingChange, onToolAction, - disabledControls, - disabledSettings, onUndo, onRedo, }: MapControlsProps) { const [isExpanded, setIsExpanded] = useState(true); const [fullScreen, setFullScreen] = useSetting("map.fullScreen"); + const userId = useUserId(); + + const isOwner = map && map.owner === userId; + + const allowMapDrawing = isOwner || mapState?.editFlags.includes("drawing"); + const allowFogDrawing = isOwner || mapState?.editFlags.includes("fog"); + const allowNoteEditing = isOwner || mapState?.editFlags.includes("notes"); + + const disabledControls: MapToolId[] = []; + if (!allowMapDrawing) { + disabledControls.push("drawing"); + } + if (!map) { + disabledControls.push("move"); + disabledControls.push("measure"); + disabledControls.push("pointer"); + disabledControls.push("select"); + } + if (!allowFogDrawing) { + disabledControls.push("fog"); + } + if (!allowMapChange) { + disabledControls.push("map"); + } + if (!allowNoteEditing) { + disabledControls.push("note"); + } + if (!map || mapActions.actionIndex < 0) { + disabledControls.push("undo"); + } + if (!map || mapActions.actionIndex === mapActions.actions.length - 1) { + disabledControls.push("redo"); + } + + const disabledSettings: Partial> = { + drawing: [], + }; + if (mapState && isEmpty(mapState.drawShapes)) { + disabledSettings.drawing?.push("erase"); + } + const toolsById: Record = { move: { id: "move", @@ -131,8 +175,8 @@ function MapContols({ ), @@ -155,8 +199,14 @@ function MapContols({ id: "history", component: ( <> - - + + ), }, @@ -218,9 +268,10 @@ function MapContols({ const Settings = toolsById[selectedToolId].SettingsComponent; if ( !Settings || - selectedToolId === "move" || - selectedToolId === "measure" || - selectedToolId === "note" + (selectedToolId !== "fog" && + selectedToolId !== "drawing" && + selectedToolId !== "pointer" && + selectedToolId !== "select") ) { return null; } @@ -277,6 +328,12 @@ function MapContols({ if (shortcuts.noteTool(event) && !disabledControls.includes("note")) { onSelectedToolChange("note"); } + if (shortcuts.redo(event) && !disabledControls.includes("redo")) { + onRedo(); + } + if (shortcuts.undo(event) && !disabledControls.includes("undo")) { + onUndo(); + } } useKeyboard(handleKeyDown); diff --git a/src/components/map/MapInteraction.tsx b/src/components/map/MapInteraction.tsx index 8fe4b1c..8d42e0c 100644 --- a/src/components/map/MapInteraction.tsx +++ b/src/components/map/MapInteraction.tsx @@ -31,7 +31,6 @@ type MapInteractionProps = { controls: React.ReactNode; selectedToolId: MapToolId; onSelectedToolChange: SelectedToolChangeEventHanlder; - disabledControls: MapToolId[]; }; function MapInteraction({ @@ -41,7 +40,6 @@ function MapInteraction({ controls, selectedToolId, onSelectedToolChange, - disabledControls, }: MapInteractionProps) { const [mapImage, mapImageStatus] = useMapImage(map); @@ -126,11 +124,7 @@ function MapInteraction({ // Stop active state on move icon from being selected event.preventDefault(); } - if ( - shortcuts.move(event) && - selectedToolId !== "move" && - !disabledControls.includes("move") - ) { + if (map && shortcuts.move(event) && selectedToolId !== "move") { event.preventDefault(); previousSelectedToolRef.current = selectedToolId; onSelectedToolChange("move"); diff --git a/src/hooks/useMapTokens.tsx b/src/hooks/useMapTokens.tsx index bf69d35..03daf88 100644 --- a/src/hooks/useMapTokens.tsx +++ b/src/hooks/useMapTokens.tsx @@ -18,20 +18,37 @@ import Token from "../components/konva/Token"; import { KonvaEventObject } from "konva/lib/Node"; import TokenMenu from "../components/token/TokenMenu"; import TokenDragOverlay from "../components/token/TokenDragOverlay"; +import { useUserId } from "../contexts/UserIdContext"; function useMapTokens( map: Map | null, mapState: MapState | null, onTokenStateChange: TokenStateChangeEventHandler, onTokenStateRemove: TokenStateRemoveHandler, - selectedToolId: MapToolId, - disabledTokens: Record + selectedToolId: MapToolId ) { const [isTokenMenuOpen, setIsTokenMenuOpen] = useState(false); const [tokenMenuOptions, setTokenMenuOptions] = useState(); const [tokenDraggingOptions, setTokenDraggingOptions] = useState(); + const userId = useUserId(); + + const disabledTokens: Record = {}; + // If we have a map and state and have the token permission disabled + // and are not the map owner + if ( + mapState && + !mapState.editFlags.includes("tokens") && + map?.owner !== userId + ) { + for (let token of Object.values(mapState.tokens)) { + if (token.owner !== userId) { + disabledTokens[token.id] = true; + } + } + } + function handleTokenMenuOpen(tokenStateId: string, tokenImage: Konva.Node) { setTokenMenuOptions({ tokenStateId, tokenImage }); setIsTokenMenuOpen(true); diff --git a/src/network/NetworkedMapAndTokens.tsx b/src/network/NetworkedMapAndTokens.tsx index b96fdce..a7e6246 100644 --- a/src/network/NetworkedMapAndTokens.tsx +++ b/src/network/NetworkedMapAndTokens.tsx @@ -217,7 +217,7 @@ function NetworkedMapAndTokens({ session }: { session: Session }) { await loadAssetManifestFromMap(newMap, newMapState); } - const [_, addActions, updateActionIndex, resetActions] = + const [mapActions, addActions, updateActionIndex, resetActions] = useMapActions(setCurrentMapState); function handleMapReset(newMapState: MapState) { @@ -360,39 +360,6 @@ function NetworkedMapAndTokens({ session }: { session: Session }) { const canChangeMap = !isLoading; - const canEditMapDrawing = - currentMap && - currentMapState && - (currentMapState.editFlags.includes("drawing") || - currentMap?.owner === userId); - - const canEditFogDrawing = - currentMap && - currentMapState && - (currentMapState.editFlags.includes("fog") || currentMap?.owner === userId); - - const canEditNotes = - currentMap && - currentMapState && - (currentMapState.editFlags.includes("notes") || - currentMap?.owner === userId); - - const disabledMapTokens: Record = {}; - // If we have a map and state and have the token permission disabled - // and are not the map owner - if ( - currentMapState && - currentMap && - !currentMapState.editFlags.includes("tokens") && - currentMap?.owner !== userId - ) { - for (let token of Object.values(currentMapState.tokens)) { - if (token.owner !== userId) { - disabledMapTokens[token.id] = true; - } - } - } - return (