From 0f2776d7749ba5acafb45ddc9fe1bb79ab130d8a Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Fri, 4 Jun 2021 21:54:26 +1000 Subject: [PATCH] Add back map edit bar and refactor select map modal edit functions --- src/components/map/MapEditBar.js | 178 ++++++++++++++++ src/components/map/SelectMapSelectButton.js | 39 ++++ src/contexts/TileDragContext.js | 4 +- src/modals/EditMapModal.js | 4 + src/modals/SelectMapModal.js | 212 ++++++-------------- 5 files changed, 283 insertions(+), 154 deletions(-) create mode 100644 src/components/map/MapEditBar.js create mode 100644 src/components/map/SelectMapSelectButton.js diff --git a/src/components/map/MapEditBar.js b/src/components/map/MapEditBar.js new file mode 100644 index 0000000..2c57f7a --- /dev/null +++ b/src/components/map/MapEditBar.js @@ -0,0 +1,178 @@ +import React, { useState, useEffect } from "react"; +import { Flex, Close, IconButton } from "theme-ui"; + +import { groupsFromIds, itemsFromGroups } from "../../helpers/group"; + +import ConfirmModal from "../../modals/ConfirmModal"; + +import ResetMapIcon from "../../icons/ResetMapIcon"; +import RemoveMapIcon from "../../icons/RemoveMapIcon"; + +import { useGroup } from "../../contexts/GroupContext"; +import { useMapData } from "../../contexts/MapDataContext"; +import { useKeyboard } from "../../contexts/KeyboardContext"; + +import shortcuts from "../../shortcuts"; + +function MapEditBar({ currentMap, disabled, onMapChange, onMapReset, onLoad }) { + const [hasMapState, setHasMapState] = useState(false); + const [hasSelectedDefaultMap, setHasSelectedDefaultMap] = useState(false); + + const { maps, mapStates, removeMaps, resetMap } = useMapData(); + + const { + groups: allGroups, + selectedGroupIds, + onGroupSelect, + openGroupId, + openGroupItems, + } = useGroup(); + + const groups = openGroupId ? openGroupItems : allGroups; + + useEffect(() => { + const selectedGroups = groupsFromIds(selectedGroupIds, groups); + const selectedMaps = itemsFromGroups(selectedGroups, maps); + const selectedMapStates = itemsFromGroups( + selectedGroups, + mapStates, + "mapId" + ); + + setHasSelectedDefaultMap( + selectedMaps.some((map) => map.type === "default") + ); + + let _hasMapState = false; + for (let state of selectedMapStates) { + if ( + Object.values(state.tokens).length > 0 || + Object.values(state.drawShapes).length > 0 || + Object.values(state.fogShapes).length > 0 || + Object.values(state.notes).length > 0 + ) { + _hasMapState = true; + break; + } + } + + setHasMapState(_hasMapState); + }, [selectedGroupIds, maps, mapStates, groups]); + + function getSelectedMaps() { + const selectedGroups = groupsFromIds(selectedGroupIds, groups); + return itemsFromGroups(selectedGroups, maps); + } + + const [isMapsRemoveModalOpen, setIsMapsRemoveModalOpen] = useState(false); + async function handleMapsRemove() { + onLoad(true); + setIsMapsRemoveModalOpen(false); + const selectedMaps = getSelectedMaps(); + const selectedMapIds = selectedMaps.map((map) => map.id); + await removeMaps(selectedMapIds); + onGroupSelect(); + // Removed the map from the map screen if needed + if (currentMap && selectedMapIds.includes(currentMap.id)) { + onMapChange(null, null); + } + onLoad(false); + } + + const [isMapsResetModalOpen, setIsMapsResetModalOpen] = useState(false); + async function handleMapsReset() { + onLoad(true); + setIsMapsResetModalOpen(false); + const selectedMaps = getSelectedMaps(); + const selectedMapIds = selectedMaps.map((map) => map.id); + for (let id of selectedMapIds) { + const newState = await resetMap(id); + // Reset the state of the current map if needed + if (currentMap && currentMap.id === id) { + onMapReset(newState); + } + } + onLoad(false); + } + + /** + * Shortcuts + */ + function handleKeyDown(event) { + if (disabled) { + return; + } + if (shortcuts.delete(event)) { + const selectedMaps = getSelectedMaps(); + // Selected maps and none are default + if ( + selectedMaps.length > 0 && + !selectedMaps.some((map) => map.type === "default") + ) { + setIsMapsResetModalOpen(false); + setIsMapsRemoveModalOpen(true); + } + } + } + + useKeyboard(handleKeyDown); + + if (selectedGroupIds.length === 0) { + return null; + } + + return ( + + onGroupSelect()} + /> + + setIsMapsResetModalOpen(true)} + disabled={!hasMapState} + > + + + setIsMapsRemoveModalOpen(true)} + disabled={hasSelectedDefaultMap} + > + + + + setIsMapsResetModalOpen(false)} + onConfirm={handleMapsReset} + confirmText="Reset" + label="Reset Selected Map(s)" + description="This will remove all fog, drawings and tokens from the selected maps." + /> + setIsMapsRemoveModalOpen(false)} + onConfirm={handleMapsRemove} + confirmText="Remove" + label="Remove Selected Map(s)" + description="This operation cannot be undone." + /> + + ); +} + +export default MapEditBar; diff --git a/src/components/map/SelectMapSelectButton.js b/src/components/map/SelectMapSelectButton.js new file mode 100644 index 0000000..80823e5 --- /dev/null +++ b/src/components/map/SelectMapSelectButton.js @@ -0,0 +1,39 @@ +import React from "react"; +import { Button } from "theme-ui"; + +import { useGroup } from "../../contexts/GroupContext"; + +import { findGroup } from "../../helpers/group"; + +function SelectMapSelectButton({ onMapSelect, disabled }) { + const { + groups: allGroups, + selectedGroupIds, + openGroupId, + openGroupItems, + } = useGroup(); + + const groups = openGroupId ? openGroupItems : allGroups; + + function handleSelectClick() { + if (selectedGroupIds.length === 1) { + const group = findGroup(groups, selectedGroupIds[0]); + if (group && group.type === "item") { + onMapSelect(group.id); + } + } + } + + return ( + + ); +} + +export default SelectMapSelectButton; diff --git a/src/contexts/TileDragContext.js b/src/contexts/TileDragContext.js index a5143c6..c8c687d 100644 --- a/src/contexts/TileDragContext.js +++ b/src/contexts/TileDragContext.js @@ -85,6 +85,7 @@ export function TileDragProvider({ onDragAdd, children }) { selectedIndices = selectedIndices.sort((a, b) => a - b); if (over.id.startsWith(GROUP_ID_PREFIX)) { + onGroupSelect(); // Handle tile group const overId = over.id.slice(9); if (overId === active.id) { @@ -96,8 +97,8 @@ export function TileDragProvider({ onDragAdd, children }) { moveGroupsInto(groups, overGroupIndex, selectedIndices), openGroupId ); - onGroupSelect(); } else if (over.id.startsWith(UNGROUP_ID_PREFIX)) { + onGroupSelect(); // Handle tile ungroup const newGroups = ungroup(allGroups, openGroupId, selectedIndices); // Close group if it was removed @@ -105,7 +106,6 @@ export function TileDragProvider({ onDragAdd, children }) { onGroupClose(); } onGroupsChange(newGroups); - onGroupSelect(); } else if (over.id.startsWith(ADD_TO_MAP_ID_PREFIX)) { onDragAdd && onDragAdd(selectedGroupIds, over.rect); } else { diff --git a/src/modals/EditMapModal.js b/src/modals/EditMapModal.js index e68a5dd..632d9e4 100644 --- a/src/modals/EditMapModal.js +++ b/src/modals/EditMapModal.js @@ -103,6 +103,10 @@ function EditMapModal({ const layout = useResponsiveLayout(); + if (!map) { + return null; + } + return ( map.id); - await removeMaps(selectedMapIds); - setSelectedGroupIds([]); - // Removed the map from the map screen if needed - if (currentMap && selectedMapIds.includes(currentMap.id)) { - onMapChange(null, null); - } - setIsLoading(false); - } - - const [isMapsResetModalOpen, setIsMapsResetModalOpen] = useState(false); - async function handleMapsReset() { - setIsLoading(true); - setIsMapsResetModalOpen(false); - const selectedMaps = getSelectedMaps(); - const selectedMapIds = selectedMaps.map((map) => map.id); - for (let id of selectedMapIds) { - const newState = await resetMap(id); - // Reset the state of the current map if needed - if (currentMap && currentMap.id === id) { - onMapReset(newState); - } - } - setIsLoading(false); - } - /** * Modal Controls */ @@ -179,69 +134,44 @@ function SelectMapModal({ onDone(); } + /** + * Map Controls + */ async function handleMapSelect(mapId) { if (isLoading) { return; } - setIsLoading(true); - const map = await getMap(mapId); - const mapState = await getMapState(mapId); - onMapChange(map, mapState); - setIsLoading(false); + if (mapId) { + setIsLoading(true); + const map = await getMap(mapId); + const mapState = await getMapState(mapId); + onMapChange(map, mapState); + setIsLoading(false); + } else { + onMapChange(null, null); + } onDone(); } + const [editingMapId, setEditingMapId] = useState(); + const [canAddDraggedMap, setCanAddDraggedMap] = useState(false); function handleGroupsSelect(groupIds) { - setSelectedGroupIds(groupIds); - if (groupIds.length === 1) { + if (!canAddDraggedMap && groupIds.length === 1) { // Only allow adding a map from dragging if there is a single group item selected const group = findGroup(mapGroups, groupIds[0]); setCanAddDraggedMap(group && group.type === "item"); - } else { + } else if (canAddDraggedMap) { setCanAddDraggedMap(false); } } - function handleSelectClick() { - if (isLoading) { - return; - } - if (selectedGroupIds.length === 1) { - const group = findGroup(mapGroups, selectedGroupIds[0]); - if (group && group.type === "item") { - handleMapSelect(group.id); - } - } else { - onMapChange(null, null); - onDone(); + function handleDragAdd(groupIds) { + if (groupIds.length === 1) { + handleMapSelect(groupIds[0]); } } - /** - * Shortcuts - */ - function handleKeyDown(event) { - if (!isOpen) { - return; - } - if (shortcuts.delete(event)) { - const selectedMaps = getSelectedMaps(); - // Selected maps and none are default - if ( - selectedMaps.length > 0 && - !selectedMaps.some((map) => map.type === "default") - ) { - // Ensure all other modals are closed - setIsEditModalOpen(false); - setIsMapsResetModalOpen(false); - setIsMapsRemoveModalOpen(true); - } - } - } - - useKeyboard(handleKeyDown); - const layout = useResponsiveLayout(); const [modalSize, setModalSize] = useState({ width: 0, height: 0 }); @@ -269,92 +199,70 @@ function SelectMapModal({ handleHeight onResize={handleModalResize} > - - - - - + + + + setIsEditModalOpen(true)} + onMapEdit={setEditingMapId} onMapSelect={handleMapSelect} /> - + setIsEditModalOpen(true)} + onMapEdit={setEditingMapId} onMapSelect={handleMapSelect} subgroup /> - - - - + + + + + {(isLoading || mapsLoading) && } setIsEditModalOpen(false)} - map={ - selectedGroupIds.length === 1 && - maps.find((map) => map.id === selectedGroupIds[0]) - } + isOpen={!!editingMapId} + onDone={() => setEditingMapId()} + map={editingMapId && maps.find((map) => map.id === editingMapId)} mapState={ - selectedGroupIds.length === 1 && - mapStates.find((state) => state.mapId === selectedGroupIds[0]) + editingMapId && + mapStates.find((state) => state.mapId === editingMapId) } onUpdateMap={updateMap} onUpdateMapState={updateMapState} /> - setIsMapsResetModalOpen(false)} - onConfirm={handleMapsReset} - confirmText="Reset" - label={`Reset ${selectedGroupIds.length} Map${ - selectedGroupIds.length > 1 ? "s" : "" - }`} - description="This will remove all fog, drawings and tokens from the selected maps." - /> - setIsMapsRemoveModalOpen(false)} - onConfirm={handleMapsRemove} - confirmText="Remove" - label="Remove Map(s)" - description="This operation cannot be undone." - />