From 183c7db1a615001f3a64c8c43a2dca48cff4152f Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Fri, 11 Jun 2021 12:20:22 +1000 Subject: [PATCH] Add group support to SelectDataModal --- src/modals/SelectDataModal.js | 220 +++++++++++++++++++++++----------- 1 file changed, 149 insertions(+), 71 deletions(-) diff --git a/src/modals/SelectDataModal.js b/src/modals/SelectDataModal.js index 5cd94ff..e0dd3fa 100644 --- a/src/modals/SelectDataModal.js +++ b/src/modals/SelectDataModal.js @@ -1,9 +1,10 @@ import React, { useEffect, useState } from "react"; -import { Box, Label, Flex, Button, Text, Checkbox, Divider } from "theme-ui"; +import { Box, Label, Flex, Button, Text, Checkbox } from "theme-ui"; import SimpleBar from "simplebar-react"; import Modal from "../components/Modal"; import LoadingOverlay from "../components/LoadingOverlay"; +import Divider from "../components/Divider"; import { getDatabase } from "../database"; @@ -17,8 +18,10 @@ function SelectDataModal({ filter, }) { const [maps, setMaps] = useState({}); + const [mapGroups, setMapGroups] = useState([]); const [tokensByMap, setTokensByMap] = useState({}); const [tokens, setTokens] = useState({}); + const [tokenGroups, setTokenGroups] = useState([]); const [isLoading, setIsLoading] = useState(false); const hasMaps = Object.values(maps).length > 0; @@ -36,7 +39,12 @@ function SelectDataModal({ .table("maps") .filter((map) => filter("maps", map, map.id)) .each((map) => { - loadedMaps[map.id] = { name: map.name, id: map.id, checked: true }; + loadedMaps[map.id] = { + name: map.name, + id: map.id, + type: map.type, + checked: true, + }; }); await db .table("states") @@ -56,17 +64,27 @@ function SelectDataModal({ loadedTokens[token.id] = { name: token.name, id: token.id, + type: token.type, checked: true, }; }); + + const mapGroup = await db.table("groups").get("maps"); + const tokenGroup = await db.table("groups").get("tokens"); + db.close(); setMaps(loadedMaps); + setMapGroups(mapGroup.items); setTokensByMap(loadedTokensByMap); + setTokenGroups(tokenGroup.items); setTokens(loadedTokens); setIsLoading(false); } else { setMaps({}); setTokens({}); + setTokenGroups([]); + setMapGroups([]); + setTokensByMap({}); } } loadData(); @@ -92,7 +110,7 @@ function SelectDataModal({ setTokens((prevTokens) => { let newTokens = { ...prevTokens }; for (let id in newTokens) { - if (id in tokensUsed) { + if (id in tokensUsed && newTokens[id].type !== "default") { newTokens[id].checked = true; } } @@ -106,11 +124,11 @@ function SelectDataModal({ onConfirm(checkedMaps, checkedTokens); } - function handleSelectMapsChanged(event) { + function handleMapsChanged(event, maps) { setMaps((prevMaps) => { let newMaps = { ...prevMaps }; - for (let id in newMaps) { - newMaps[id].checked = event.target.checked; + for (let map of maps) { + newMaps[map.id].checked = event.target.checked; } return newMaps; }); @@ -118,26 +136,17 @@ function SelectDataModal({ if (!event.target.checked && !tokensSelectChecked) { setTokens((prevTokens) => { let newTokens = { ...prevTokens }; + let tempUsedCount = { ...tokenUsedCount }; for (let id in newTokens) { - newTokens[id].checked = false; - } - return newTokens; - }); - } - } - - function handleMapChange(event, map) { - setMaps((prevMaps) => ({ - ...prevMaps, - [map.id]: { ...map, checked: event.target.checked }, - })); - // If all token select is unchecked then ensure tokens assosiated to this map are unchecked - if (!event.target.checked && !tokensSelectChecked) { - setTokens((prevTokens) => { - let newTokens = { ...prevTokens }; - for (let id in newTokens) { - if (tokensByMap[map.id].has(id) && tokenUsedCount[id] === 1) { - newTokens[id].checked = false; + for (let map of maps) { + if (tokensByMap[map.id].has(id)) { + if (tempUsedCount[id] > 1) { + tempUsedCount[id] -= 1; + } else if (tempUsedCount[id] === 1) { + tempUsedCount[id] = 0; + newTokens[id].checked = false; + } + } } } return newTokens; @@ -145,31 +154,126 @@ function SelectDataModal({ } } - function handleSelectTokensChange(event) { + function handleTokensChanged(event, tokens) { setTokens((prevTokens) => { let newTokens = { ...prevTokens }; - for (let id in newTokens) { - if (!(id in tokenUsedCount)) { - newTokens[id].checked = event.target.checked; + for (let token of tokens) { + if (!(token.id in tokenUsedCount) || token.type === "default") { + newTokens[token.id].checked = event.target.checked; } } return newTokens; }); } - function handleTokenChange(event, token) { - setTokens((prevTokens) => ({ - ...prevTokens, - [token.id]: { ...token, checked: event.target.checked }, - })); - } - // Some tokens are checked not by maps or all tokens are checked by maps const tokensSelectChecked = Object.values(tokens).some( (token) => !(token.id in tokenUsedCount) && token.checked ) || Object.values(tokens).every((token) => token.id in tokenUsedCount); + function renderGroupContainer(group, checked, renderItem, onGroupChange) { + return ( + + + + {group.items.map(renderItem)} + + + + + + ); + } + + function renderMapGroup(group) { + if (group.type === "item") { + const map = maps[group.id]; + return ( + + ); + } else { + return renderGroupContainer( + group, + group.items.some((item) => maps[item.id].checked), + renderMapGroup, + (e, group) => + handleMapsChanged( + e, + group.items.map((group) => maps[group.id]) + ) + ); + } + } + + function renderTokenGroup(group) { + if (group.type === "item") { + const token = tokens[group.id]; + return ( + + + {token.id in tokenUsedCount && token.type !== "default" && ( + + Token used in {tokenUsedCount[token.id]} selected map + {tokenUsedCount[token.id] > 1 && "s"} + + )} + + ); + } else { + const checked = + group.items.some( + (item) => !(item.id in tokenUsedCount) && tokens[item.id].checked + ) || group.items.every((item) => item.id in tokenUsedCount); + return renderGroupContainer( + group, + checked, + renderTokenGroup, + (e, group) => + handleTokensChanged( + e, + group.items.map((group) => tokens[group.id]) + ) + ); + } + } + return ( map.checked)} - onChange={handleSelectMapsChanged} + onChange={(e) => + handleMapsChanged(e, Object.values(maps)) + } /> Maps - {Object.values(maps).map((map) => ( - - ))} + {mapGroups.map(renderMapGroup)} )} - {hasMaps && hasTokens && } + {hasMaps && hasTokens && } {hasTokens && ( <> - {Object.values(tokens).map((token) => ( - - - {token.id in tokenUsedCount && ( - - Token used in {tokenUsedCount[token.id]} selected map - {tokenUsedCount[token.id] > 1 && "s"} - - )} - - ))} + {tokenGroups.map(renderTokenGroup)} )}