diff --git a/src/components/map/MapTile.js b/src/components/map/MapTile.js index 5affdf0..640b8aa 100644 --- a/src/components/map/MapTile.js +++ b/src/components/map/MapTile.js @@ -6,7 +6,7 @@ import ResetMapIcon from "../../icons/ResetMapIcon"; import ExpandMoreDotIcon from "../../icons/ExpandMoreDotIcon"; import useDataSource from "../../helpers/useDataSource"; -import { mapSources as defaultMapSources } from "../../maps"; +import { mapSources as defaultMapSources, unknownSource } from "../../maps"; function MapTile({ map, @@ -17,7 +17,7 @@ function MapTile({ onMapReset, onDone, }) { - const mapSource = useDataSource(map, defaultMapSources); + const mapSource = useDataSource(map, defaultMapSources, unknownSource); const [isMapTileMenuOpen, setIsTileMenuOpen] = useState(false); const isDefault = map.type === "default"; const hasMapState = diff --git a/src/components/map/MapToken.js b/src/components/map/MapToken.js index 7161597..f4d80dc 100644 --- a/src/components/map/MapToken.js +++ b/src/components/map/MapToken.js @@ -9,11 +9,11 @@ import useDataSource from "../../helpers/useDataSource"; import AuthContext from "../../contexts/AuthContext"; -import { tokenSources } from "../../tokens"; +import { tokenSources, unknownSource } from "../../tokens"; function MapToken({ token, tokenState, tokenSizePercent, className }) { const { userId } = useContext(AuthContext); - const imageSource = useDataSource(token, tokenSources); + const imageSource = useDataSource(token, tokenSources, unknownSource); const imageRef = useRef(); // Stop touch to prevent 3d touch gesutre on iOS diff --git a/src/components/token/ListToken.js b/src/components/token/ListToken.js index bbdb3a2..690d593 100644 --- a/src/components/token/ListToken.js +++ b/src/components/token/ListToken.js @@ -4,10 +4,10 @@ import { Box, Image } from "theme-ui"; import usePreventTouch from "../../helpers/usePreventTouch"; import useDataSource from "../../helpers/useDataSource"; -import { tokenSources } from "../../tokens"; +import { tokenSources, unknownSource } from "../../tokens"; function ListToken({ token, className }) { - const imageSource = useDataSource(token, tokenSources); + const imageSource = useDataSource(token, tokenSources, unknownSource); const imageRef = useRef(); // Stop touch to prevent 3d touch gesutre on iOS diff --git a/src/components/token/TokenTile.js b/src/components/token/TokenTile.js index 78df16b..4d521db 100644 --- a/src/components/token/TokenTile.js +++ b/src/components/token/TokenTile.js @@ -4,10 +4,13 @@ import { Flex, Image, Text, Box, IconButton } from "theme-ui"; import RemoveMapIcon from "../../icons/RemoveMapIcon"; import useDataSource from "../../helpers/useDataSource"; -import { tokenSources as defaultTokenSources } from "../../tokens"; +import { + tokenSources as defaultTokenSources, + unknownSource, +} from "../../tokens"; function TokenTile({ token, isSelected, onTokenSelect, onTokenRemove }) { - const tokenSource = useDataSource(token, defaultTokenSources); + const tokenSource = useDataSource(token, defaultTokenSources, unknownSource); const isDefault = token.type === "default"; return ( diff --git a/src/contexts/TokenDataContext.js b/src/contexts/TokenDataContext.js index 096d006..31ad185 100644 --- a/src/contexts/TokenDataContext.js +++ b/src/contexts/TokenDataContext.js @@ -46,7 +46,6 @@ export function TokenDataProvider({ children }) { } async function removeToken(id) { - // TODO when removing token also remove it from all states that reference it and replicate await database.table("tokens").delete(id); setTokens((prevTokens) => { const filtered = prevTokens.filter((token) => token.id !== id); diff --git a/src/helpers/useDataSource.js b/src/helpers/useDataSource.js index 4af57a1..6dc39b8 100644 --- a/src/helpers/useDataSource.js +++ b/src/helpers/useDataSource.js @@ -2,14 +2,14 @@ import { useEffect, useState } from "react"; // Helper function to load either file or default data // into a URL and ensure that it is revoked if needed -function useDataSource(data, defaultSources) { +function useDataSource(data, defaultSources, unknownSource) { const [dataSource, setDataSource] = useState(null); useEffect(() => { if (!data) { - setDataSource(null); + setDataSource(unknownSource); return; } - let url = null; + let url = unknownSource; if (data.type === "file") { url = URL.createObjectURL(new Blob([data.file])); } else if (data.type === "default") { @@ -22,7 +22,7 @@ function useDataSource(data, defaultSources) { URL.revokeObjectURL(url); } }; - }, [data, defaultSources]); + }, [data, defaultSources, unknownSource]); return dataSource; } diff --git a/src/maps/Unknown Grid 22x22.jpg b/src/maps/Unknown Grid 22x22.jpg new file mode 100644 index 0000000..d4e9933 Binary files /dev/null and b/src/maps/Unknown Grid 22x22.jpg differ diff --git a/src/maps/index.js b/src/maps/index.js index 9fe93d7..4fdaf4d 100644 --- a/src/maps/index.js +++ b/src/maps/index.js @@ -5,6 +5,8 @@ import stoneImage from "./Stone Grid 22x22.jpg"; import waterImage from "./Water Grid 22x22.jpg"; import woodImage from "./Wood Grid 22x22.jpg"; +import unknownImage from "./Unknown Grid 22x22.jpg"; + export const mapSources = { blank: blankImage, grass: grassImage, @@ -23,3 +25,5 @@ export const maps = Object.keys(mapSources).map((key) => ({ height: 1024, type: "default", })); + +export const unknownSource = unknownImage; diff --git a/src/modals/SettingsModal.js b/src/modals/SettingsModal.js index 43fbe55..61a75ee 100644 --- a/src/modals/SettingsModal.js +++ b/src/modals/SettingsModal.js @@ -18,7 +18,26 @@ function SettingsModal({ isOpen, onRequestClose }) { async function handleClearCache() { await database.table("maps").where("owner").notEqual(userId).delete(); - // TODO: With custom tokens look up all tokens that aren't being used in a state + // Find all other peoples tokens who aren't benig used in a map state and delete them + const tokens = await database + .table("tokens") + .where("owner") + .notEqual(userId) + .toArray(); + const states = await database.table("states").toArray(); + for (let token of tokens) { + let inUse = false; + for (let state of states) { + for (let tokenState of Object.values(state.tokens)) { + if (token.id === tokenState.tokenId) { + inUse = true; + } + } + } + if (!inUse) { + database.table("tokens").delete(token.id); + } + } window.location.reload(); } diff --git a/src/routes/Game.js b/src/routes/Game.js index 39b10fc..edc5cb6 100644 --- a/src/routes/Game.js +++ b/src/routes/Game.js @@ -219,9 +219,11 @@ function Game() { ) { sentTokens[tokenState.tokenId] = true; const token = getToken(tokenState.tokenId); - // Omit file from token peer will request file if needed - const { file, ...rest } = token; - peer.connection.send({ id: "token", data: rest }); + if (token) { + // Omit file from token peer will request file if needed + const { file, ...rest } = token; + peer.connection.send({ id: "token", data: rest }); + } } } } diff --git a/src/tokens/Unknown.png b/src/tokens/Unknown.png new file mode 100644 index 0000000..8987eed Binary files /dev/null and b/src/tokens/Unknown.png differ diff --git a/src/tokens/index.js b/src/tokens/index.js index c6a3a0f..8293d84 100644 --- a/src/tokens/index.js +++ b/src/tokens/index.js @@ -29,6 +29,7 @@ import titan from "./Titan.png"; import undead from "./Undead.png"; import warlock from "./Warlock.png"; import wizard from "./Wizard.png"; +import unknown from "./Unknown.png"; export const tokenSources = { barbarian, @@ -69,3 +70,5 @@ export const tokens = Object.keys(tokenSources).map((key) => ({ name: key.charAt(0).toUpperCase() + key.slice(1), type: "default", })); + +export const unknownSource = unknown;