Changed data contexts to use useCallback and fixed performance issues when changing party state
This commit is contained in:
parent
b443cdcf09
commit
3abf9c62fa
@ -1,4 +1,10 @@
|
|||||||
import React, { useEffect, useState, useContext } from "react";
|
import React, {
|
||||||
|
useEffect,
|
||||||
|
useState,
|
||||||
|
useContext,
|
||||||
|
useCallback,
|
||||||
|
useRef,
|
||||||
|
} from "react";
|
||||||
import * as Comlink from "comlink";
|
import * as Comlink from "comlink";
|
||||||
|
|
||||||
import AuthContext from "./AuthContext";
|
import AuthContext from "./AuthContext";
|
||||||
@ -26,6 +32,8 @@ const defaultMapState = {
|
|||||||
notes: {},
|
notes: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const worker = Comlink.wrap(new DatabaseWorker());
|
||||||
|
|
||||||
export function MapDataProvider({ children }) {
|
export function MapDataProvider({ children }) {
|
||||||
const { database, databaseStatus } = useContext(DatabaseContext);
|
const { database, databaseStatus } = useContext(DatabaseContext);
|
||||||
const { userId } = useContext(AuthContext);
|
const { userId } = useContext(AuthContext);
|
||||||
@ -65,7 +73,6 @@ export function MapDataProvider({ children }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadMaps() {
|
async function loadMaps() {
|
||||||
const worker = Comlink.wrap(new DatabaseWorker());
|
|
||||||
await worker.loadData("maps");
|
await worker.loadData("maps");
|
||||||
const storedMaps = await worker.data;
|
const storedMaps = await worker.data;
|
||||||
const sortedMaps = storedMaps.sort((a, b) => b.created - a.created);
|
const sortedMaps = storedMaps.sort((a, b) => b.created - a.created);
|
||||||
@ -80,139 +87,28 @@ export function MapDataProvider({ children }) {
|
|||||||
loadMaps();
|
loadMaps();
|
||||||
}, [userId, database, databaseStatus]);
|
}, [userId, database, databaseStatus]);
|
||||||
|
|
||||||
/**
|
const mapsRef = useRef(maps);
|
||||||
* Adds a map to the database, also adds an assosiated state for that map
|
useEffect(() => {
|
||||||
* @param {Object} map map to add
|
mapsRef.current = maps;
|
||||||
*/
|
}, [maps]);
|
||||||
async function addMap(map) {
|
|
||||||
await database.table("maps").add(map);
|
|
||||||
const state = { ...defaultMapState, mapId: map.id };
|
|
||||||
await database.table("states").add(state);
|
|
||||||
setMaps((prevMaps) => [map, ...prevMaps]);
|
|
||||||
setMapStates((prevStates) => [state, ...prevStates]);
|
|
||||||
if (map.owner !== userId) {
|
|
||||||
await updateCache();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function removeMap(id) {
|
const getMap = useCallback((mapId) => {
|
||||||
await database.table("maps").delete(id);
|
return mapsRef.current.find((map) => map.id === mapId);
|
||||||
await database.table("states").delete(id);
|
}, []);
|
||||||
setMaps((prevMaps) => {
|
|
||||||
const filtered = prevMaps.filter((map) => map.id !== id);
|
|
||||||
return filtered;
|
|
||||||
});
|
|
||||||
setMapStates((prevMapsStates) => {
|
|
||||||
const filtered = prevMapsStates.filter((state) => state.mapId !== id);
|
|
||||||
return filtered;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function removeMaps(ids) {
|
const getMapFromDB = useCallback(
|
||||||
await database.table("maps").bulkDelete(ids);
|
async (mapId) => {
|
||||||
await database.table("states").bulkDelete(ids);
|
let map = await database.table("maps").get(mapId);
|
||||||
setMaps((prevMaps) => {
|
return map;
|
||||||
const filtered = prevMaps.filter((map) => !ids.includes(map.id));
|
},
|
||||||
return filtered;
|
[database]
|
||||||
});
|
);
|
||||||
setMapStates((prevMapsStates) => {
|
|
||||||
const filtered = prevMapsStates.filter(
|
|
||||||
(state) => !ids.includes(state.mapId)
|
|
||||||
);
|
|
||||||
return filtered;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function resetMap(id) {
|
|
||||||
const state = { ...defaultMapState, mapId: id };
|
|
||||||
await database.table("states").put(state);
|
|
||||||
setMapStates((prevMapStates) => {
|
|
||||||
const newStates = [...prevMapStates];
|
|
||||||
const i = newStates.findIndex((state) => state.mapId === id);
|
|
||||||
if (i > -1) {
|
|
||||||
newStates[i] = state;
|
|
||||||
}
|
|
||||||
return newStates;
|
|
||||||
});
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function updateMap(id, update) {
|
|
||||||
// fake-indexeddb throws an error when updating maps in production.
|
|
||||||
// Catch that error and use put when it fails
|
|
||||||
try {
|
|
||||||
await database.table("maps").update(id, update);
|
|
||||||
} catch (error) {
|
|
||||||
// if (error.name !== "QuotaExceededError") {
|
|
||||||
const map = (await getMapFromDB(id)) || {};
|
|
||||||
await database.table("maps").put({ ...map, id, ...update });
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
setMaps((prevMaps) => {
|
|
||||||
const newMaps = [...prevMaps];
|
|
||||||
const i = newMaps.findIndex((map) => map.id === id);
|
|
||||||
if (i > -1) {
|
|
||||||
newMaps[i] = { ...newMaps[i], ...update };
|
|
||||||
}
|
|
||||||
return newMaps;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function updateMaps(ids, update) {
|
|
||||||
await Promise.all(
|
|
||||||
ids.map((id) => database.table("maps").update(id, update))
|
|
||||||
);
|
|
||||||
setMaps((prevMaps) => {
|
|
||||||
const newMaps = [...prevMaps];
|
|
||||||
for (let id of ids) {
|
|
||||||
const i = newMaps.findIndex((map) => map.id === id);
|
|
||||||
if (i > -1) {
|
|
||||||
newMaps[i] = { ...newMaps[i], ...update };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newMaps;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function updateMapState(id, update) {
|
|
||||||
await database.table("states").update(id, update);
|
|
||||||
setMapStates((prevMapStates) => {
|
|
||||||
const newStates = [...prevMapStates];
|
|
||||||
const i = newStates.findIndex((state) => state.mapId === id);
|
|
||||||
if (i > -1) {
|
|
||||||
newStates[i] = { ...newStates[i], ...update };
|
|
||||||
}
|
|
||||||
return newStates;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a map to the database if none exists or replaces a map if it already exists
|
|
||||||
* Note: this does not add a map state to do that use AddMap
|
|
||||||
* @param {Object} map the map to put
|
|
||||||
*/
|
|
||||||
async function putMap(map) {
|
|
||||||
await database.table("maps").put(map);
|
|
||||||
setMaps((prevMaps) => {
|
|
||||||
const newMaps = [...prevMaps];
|
|
||||||
const i = newMaps.findIndex((m) => m.id === map.id);
|
|
||||||
if (i > -1) {
|
|
||||||
newMaps[i] = { ...newMaps[i], ...map };
|
|
||||||
} else {
|
|
||||||
newMaps.unshift(map);
|
|
||||||
}
|
|
||||||
return newMaps;
|
|
||||||
});
|
|
||||||
if (map.owner !== userId) {
|
|
||||||
await updateCache();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keep up to cachedMapMax amount of maps that you don't own
|
* Keep up to cachedMapMax amount of maps that you don't own
|
||||||
* Sorted by when they we're last used
|
* Sorted by when they we're last used
|
||||||
*/
|
*/
|
||||||
async function updateCache() {
|
const updateCache = useCallback(async () => {
|
||||||
const cachedMaps = await database
|
const cachedMaps = await database
|
||||||
.table("maps")
|
.table("maps")
|
||||||
.where("owner")
|
.where("owner")
|
||||||
@ -228,16 +124,157 @@ export function MapDataProvider({ children }) {
|
|||||||
return prevMaps.filter((map) => !idsToDelete.includes(map.id));
|
return prevMaps.filter((map) => !idsToDelete.includes(map.id));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}, [database, userId]);
|
||||||
|
|
||||||
function getMap(mapId) {
|
/**
|
||||||
return maps.find((map) => map.id === mapId);
|
* Adds a map to the database, also adds an assosiated state for that map
|
||||||
}
|
* @param {Object} map map to add
|
||||||
|
*/
|
||||||
|
const addMap = useCallback(
|
||||||
|
async (map) => {
|
||||||
|
await database.table("maps").add(map);
|
||||||
|
const state = { ...defaultMapState, mapId: map.id };
|
||||||
|
await database.table("states").add(state);
|
||||||
|
setMaps((prevMaps) => [map, ...prevMaps]);
|
||||||
|
setMapStates((prevStates) => [state, ...prevStates]);
|
||||||
|
if (map.owner !== userId) {
|
||||||
|
await updateCache();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[database, updateCache, userId]
|
||||||
|
);
|
||||||
|
|
||||||
async function getMapFromDB(mapId) {
|
const removeMap = useCallback(
|
||||||
let map = await database.table("maps").get(mapId);
|
async (id) => {
|
||||||
return map;
|
await database.table("maps").delete(id);
|
||||||
}
|
await database.table("states").delete(id);
|
||||||
|
setMaps((prevMaps) => {
|
||||||
|
const filtered = prevMaps.filter((map) => map.id !== id);
|
||||||
|
return filtered;
|
||||||
|
});
|
||||||
|
setMapStates((prevMapsStates) => {
|
||||||
|
const filtered = prevMapsStates.filter((state) => state.mapId !== id);
|
||||||
|
return filtered;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[database]
|
||||||
|
);
|
||||||
|
|
||||||
|
const removeMaps = useCallback(
|
||||||
|
async (ids) => {
|
||||||
|
await database.table("maps").bulkDelete(ids);
|
||||||
|
await database.table("states").bulkDelete(ids);
|
||||||
|
setMaps((prevMaps) => {
|
||||||
|
const filtered = prevMaps.filter((map) => !ids.includes(map.id));
|
||||||
|
return filtered;
|
||||||
|
});
|
||||||
|
setMapStates((prevMapsStates) => {
|
||||||
|
const filtered = prevMapsStates.filter(
|
||||||
|
(state) => !ids.includes(state.mapId)
|
||||||
|
);
|
||||||
|
return filtered;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[database]
|
||||||
|
);
|
||||||
|
|
||||||
|
const resetMap = useCallback(
|
||||||
|
async (id) => {
|
||||||
|
const state = { ...defaultMapState, mapId: id };
|
||||||
|
await database.table("states").put(state);
|
||||||
|
setMapStates((prevMapStates) => {
|
||||||
|
const newStates = [...prevMapStates];
|
||||||
|
const i = newStates.findIndex((state) => state.mapId === id);
|
||||||
|
if (i > -1) {
|
||||||
|
newStates[i] = state;
|
||||||
|
}
|
||||||
|
return newStates;
|
||||||
|
});
|
||||||
|
return state;
|
||||||
|
},
|
||||||
|
[database]
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateMap = useCallback(
|
||||||
|
async (id, update) => {
|
||||||
|
// fake-indexeddb throws an error when updating maps in production.
|
||||||
|
// Catch that error and use put when it fails
|
||||||
|
try {
|
||||||
|
await database.table("maps").update(id, update);
|
||||||
|
} catch (error) {
|
||||||
|
const map = (await getMapFromDB(id)) || {};
|
||||||
|
await database.table("maps").put({ ...map, id, ...update });
|
||||||
|
}
|
||||||
|
setMaps((prevMaps) => {
|
||||||
|
const newMaps = [...prevMaps];
|
||||||
|
const i = newMaps.findIndex((map) => map.id === id);
|
||||||
|
if (i > -1) {
|
||||||
|
newMaps[i] = { ...newMaps[i], ...update };
|
||||||
|
}
|
||||||
|
return newMaps;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[database, getMapFromDB]
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateMaps = useCallback(
|
||||||
|
async (ids, update) => {
|
||||||
|
await Promise.all(
|
||||||
|
ids.map((id) => database.table("maps").update(id, update))
|
||||||
|
);
|
||||||
|
setMaps((prevMaps) => {
|
||||||
|
const newMaps = [...prevMaps];
|
||||||
|
for (let id of ids) {
|
||||||
|
const i = newMaps.findIndex((map) => map.id === id);
|
||||||
|
if (i > -1) {
|
||||||
|
newMaps[i] = { ...newMaps[i], ...update };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newMaps;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[database]
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateMapState = useCallback(
|
||||||
|
async (id, update) => {
|
||||||
|
await database.table("states").update(id, update);
|
||||||
|
setMapStates((prevMapStates) => {
|
||||||
|
const newStates = [...prevMapStates];
|
||||||
|
const i = newStates.findIndex((state) => state.mapId === id);
|
||||||
|
if (i > -1) {
|
||||||
|
newStates[i] = { ...newStates[i], ...update };
|
||||||
|
}
|
||||||
|
return newStates;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[database]
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a map to the database if none exists or replaces a map if it already exists
|
||||||
|
* Note: this does not add a map state to do that use AddMap
|
||||||
|
* @param {Object} map the map to put
|
||||||
|
*/
|
||||||
|
const putMap = useCallback(
|
||||||
|
async (map) => {
|
||||||
|
await database.table("maps").put(map);
|
||||||
|
setMaps((prevMaps) => {
|
||||||
|
const newMaps = [...prevMaps];
|
||||||
|
const i = newMaps.findIndex((m) => m.id === map.id);
|
||||||
|
if (i > -1) {
|
||||||
|
newMaps[i] = { ...newMaps[i], ...map };
|
||||||
|
} else {
|
||||||
|
newMaps.unshift(map);
|
||||||
|
}
|
||||||
|
return newMaps;
|
||||||
|
});
|
||||||
|
if (map.owner !== userId) {
|
||||||
|
await updateCache();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[database, updateCache, userId]
|
||||||
|
);
|
||||||
|
|
||||||
const ownedMaps = maps.filter((map) => map.owner === userId);
|
const ownedMaps = maps.filter((map) => map.owner === userId);
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
import React, { useEffect, useState, useContext } from "react";
|
import React, {
|
||||||
|
useEffect,
|
||||||
|
useState,
|
||||||
|
useContext,
|
||||||
|
useCallback,
|
||||||
|
useRef,
|
||||||
|
} from "react";
|
||||||
import * as Comlink from "comlink";
|
import * as Comlink from "comlink";
|
||||||
|
|
||||||
import AuthContext from "./AuthContext";
|
import AuthContext from "./AuthContext";
|
||||||
@ -12,6 +18,8 @@ const TokenDataContext = React.createContext();
|
|||||||
|
|
||||||
const cachedTokenMax = 100;
|
const cachedTokenMax = 100;
|
||||||
|
|
||||||
|
const worker = Comlink.wrap(new DatabaseWorker());
|
||||||
|
|
||||||
export function TokenDataProvider({ children }) {
|
export function TokenDataProvider({ children }) {
|
||||||
const { database, databaseStatus } = useContext(DatabaseContext);
|
const { database, databaseStatus } = useContext(DatabaseContext);
|
||||||
const { userId } = useContext(AuthContext);
|
const { userId } = useContext(AuthContext);
|
||||||
@ -37,7 +45,6 @@ export function TokenDataProvider({ children }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadTokens() {
|
async function loadTokens() {
|
||||||
const worker = Comlink.wrap(new DatabaseWorker());
|
|
||||||
await worker.loadData("tokens");
|
await worker.loadData("tokens");
|
||||||
const storedTokens = await worker.data;
|
const storedTokens = await worker.data;
|
||||||
const sortedTokens = storedTokens.sort((a, b) => b.created - a.created);
|
const sortedTokens = storedTokens.sort((a, b) => b.created - a.created);
|
||||||
@ -50,82 +57,28 @@ export function TokenDataProvider({ children }) {
|
|||||||
loadTokens();
|
loadTokens();
|
||||||
}, [userId, database, databaseStatus]);
|
}, [userId, database, databaseStatus]);
|
||||||
|
|
||||||
async function addToken(token) {
|
const tokensRef = useRef(tokens);
|
||||||
await database.table("tokens").add(token);
|
useEffect(() => {
|
||||||
setTokens((prevTokens) => [token, ...prevTokens]);
|
tokensRef.current = tokens;
|
||||||
if (token.owner !== userId) {
|
}, [tokens]);
|
||||||
await updateCache();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function removeToken(id) {
|
const getToken = useCallback((tokenId) => {
|
||||||
await database.table("tokens").delete(id);
|
return tokensRef.current.find((token) => token.id === tokenId);
|
||||||
setTokens((prevTokens) => {
|
}, []);
|
||||||
const filtered = prevTokens.filter((token) => token.id !== id);
|
|
||||||
return filtered;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function removeTokens(ids) {
|
const getTokenFromDB = useCallback(
|
||||||
await database.table("tokens").bulkDelete(ids);
|
async (tokenId) => {
|
||||||
setTokens((prevTokens) => {
|
let token = await database.table("tokens").get(tokenId);
|
||||||
const filtered = prevTokens.filter((token) => !ids.includes(token.id));
|
return token;
|
||||||
return filtered;
|
},
|
||||||
});
|
[database]
|
||||||
}
|
);
|
||||||
|
|
||||||
async function updateToken(id, update) {
|
|
||||||
const change = { ...update, lastModified: Date.now() };
|
|
||||||
await database.table("tokens").update(id, change);
|
|
||||||
setTokens((prevTokens) => {
|
|
||||||
const newTokens = [...prevTokens];
|
|
||||||
const i = newTokens.findIndex((token) => token.id === id);
|
|
||||||
if (i > -1) {
|
|
||||||
newTokens[i] = { ...newTokens[i], ...change };
|
|
||||||
}
|
|
||||||
return newTokens;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function updateTokens(ids, update) {
|
|
||||||
const change = { ...update, lastModified: Date.now() };
|
|
||||||
await Promise.all(
|
|
||||||
ids.map((id) => database.table("tokens").update(id, change))
|
|
||||||
);
|
|
||||||
setTokens((prevTokens) => {
|
|
||||||
const newTokens = [...prevTokens];
|
|
||||||
for (let id of ids) {
|
|
||||||
const i = newTokens.findIndex((token) => token.id === id);
|
|
||||||
if (i > -1) {
|
|
||||||
newTokens[i] = { ...newTokens[i], ...change };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newTokens;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function putToken(token) {
|
|
||||||
await database.table("tokens").put(token);
|
|
||||||
setTokens((prevTokens) => {
|
|
||||||
const newTokens = [...prevTokens];
|
|
||||||
const i = newTokens.findIndex((t) => t.id === token.id);
|
|
||||||
if (i > -1) {
|
|
||||||
newTokens[i] = { ...newTokens[i], ...token };
|
|
||||||
} else {
|
|
||||||
newTokens.unshift(token);
|
|
||||||
}
|
|
||||||
return newTokens;
|
|
||||||
});
|
|
||||||
if (token.owner !== userId) {
|
|
||||||
await updateCache();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keep up to cachedTokenMax amount of tokens that you don't own
|
* Keep up to cachedTokenMax amount of tokens that you don't own
|
||||||
* Sorted by when they we're last used
|
* Sorted by when they we're last used
|
||||||
*/
|
*/
|
||||||
async function updateCache() {
|
const updateCache = useCallback(async () => {
|
||||||
const cachedTokens = await database
|
const cachedTokens = await database
|
||||||
.table("tokens")
|
.table("tokens")
|
||||||
.where("owner")
|
.where("owner")
|
||||||
@ -141,11 +94,96 @@ export function TokenDataProvider({ children }) {
|
|||||||
return prevTokens.filter((token) => !idsToDelete.includes(token.id));
|
return prevTokens.filter((token) => !idsToDelete.includes(token.id));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}, [database, userId]);
|
||||||
|
|
||||||
function getToken(tokenId) {
|
const addToken = useCallback(
|
||||||
return tokens.find((token) => token.id === tokenId);
|
async (token) => {
|
||||||
}
|
await database.table("tokens").add(token);
|
||||||
|
setTokens((prevTokens) => [token, ...prevTokens]);
|
||||||
|
if (token.owner !== userId) {
|
||||||
|
await updateCache();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[database, updateCache, userId]
|
||||||
|
);
|
||||||
|
|
||||||
|
const removeToken = useCallback(
|
||||||
|
async (id) => {
|
||||||
|
await database.table("tokens").delete(id);
|
||||||
|
setTokens((prevTokens) => {
|
||||||
|
const filtered = prevTokens.filter((token) => token.id !== id);
|
||||||
|
return filtered;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[database]
|
||||||
|
);
|
||||||
|
|
||||||
|
const removeTokens = useCallback(
|
||||||
|
async (ids) => {
|
||||||
|
await database.table("tokens").bulkDelete(ids);
|
||||||
|
setTokens((prevTokens) => {
|
||||||
|
const filtered = prevTokens.filter((token) => !ids.includes(token.id));
|
||||||
|
return filtered;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[database]
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateToken = useCallback(
|
||||||
|
async (id, update) => {
|
||||||
|
const change = { ...update, lastModified: Date.now() };
|
||||||
|
await database.table("tokens").update(id, change);
|
||||||
|
setTokens((prevTokens) => {
|
||||||
|
const newTokens = [...prevTokens];
|
||||||
|
const i = newTokens.findIndex((token) => token.id === id);
|
||||||
|
if (i > -1) {
|
||||||
|
newTokens[i] = { ...newTokens[i], ...change };
|
||||||
|
}
|
||||||
|
return newTokens;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[database]
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateTokens = useCallback(
|
||||||
|
async (ids, update) => {
|
||||||
|
const change = { ...update, lastModified: Date.now() };
|
||||||
|
await Promise.all(
|
||||||
|
ids.map((id) => database.table("tokens").update(id, change))
|
||||||
|
);
|
||||||
|
setTokens((prevTokens) => {
|
||||||
|
const newTokens = [...prevTokens];
|
||||||
|
for (let id of ids) {
|
||||||
|
const i = newTokens.findIndex((token) => token.id === id);
|
||||||
|
if (i > -1) {
|
||||||
|
newTokens[i] = { ...newTokens[i], ...change };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newTokens;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[database]
|
||||||
|
);
|
||||||
|
|
||||||
|
const putToken = useCallback(
|
||||||
|
async (token) => {
|
||||||
|
await database.table("tokens").put(token);
|
||||||
|
setTokens((prevTokens) => {
|
||||||
|
const newTokens = [...prevTokens];
|
||||||
|
const i = newTokens.findIndex((t) => t.id === token.id);
|
||||||
|
if (i > -1) {
|
||||||
|
newTokens[i] = { ...newTokens[i], ...token };
|
||||||
|
} else {
|
||||||
|
newTokens.unshift(token);
|
||||||
|
}
|
||||||
|
return newTokens;
|
||||||
|
});
|
||||||
|
if (token.owner !== userId) {
|
||||||
|
await updateCache();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[database, updateCache, userId]
|
||||||
|
);
|
||||||
|
|
||||||
const ownedTokens = tokens.filter((token) => token.owner === userId);
|
const ownedTokens = tokens.filter((token) => token.owner === userId);
|
||||||
|
|
||||||
@ -166,6 +204,7 @@ export function TokenDataProvider({ children }) {
|
|||||||
getToken,
|
getToken,
|
||||||
tokensById,
|
tokensById,
|
||||||
tokensLoading,
|
tokensLoading,
|
||||||
|
getTokenFromDB,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -36,9 +36,13 @@ function NetworkedMapAndTokens({ session }) {
|
|||||||
} = useContext(MapLoadingContext);
|
} = useContext(MapLoadingContext);
|
||||||
|
|
||||||
const { putToken, getToken, updateToken } = useContext(TokenDataContext);
|
const { putToken, getToken, updateToken } = useContext(TokenDataContext);
|
||||||
const { putMap, updateMap, getMapFromDB, updateMapState } = useContext(
|
const {
|
||||||
MapDataContext
|
putMap,
|
||||||
);
|
updateMap,
|
||||||
|
getMap,
|
||||||
|
getMapFromDB,
|
||||||
|
updateMapState,
|
||||||
|
} = useContext(MapDataContext);
|
||||||
|
|
||||||
const [currentMap, setCurrentMap] = useState(null);
|
const [currentMap, setCurrentMap] = useState(null);
|
||||||
const [currentMapState, setCurrentMapState] = useNetworkedState(
|
const [currentMapState, setCurrentMapState] = useNetworkedState(
|
||||||
@ -129,8 +133,10 @@ function NetworkedMapAndTokens({ session }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (asset.type === "map") {
|
if (asset.type === "map") {
|
||||||
const cachedMap = await getMapFromDB(asset.id);
|
const cachedMap = getMap(asset.id);
|
||||||
if (cachedMap && cachedMap.lastModified >= asset.lastModified) {
|
if (cachedMap && cachedMap.lastModified === asset.lastModified) {
|
||||||
|
continue;
|
||||||
|
} else if (cachedMap && cachedMap.lastModified > asset.lastModified) {
|
||||||
// Update last used for cache invalidation
|
// Update last used for cache invalidation
|
||||||
const lastUsed = Date.now();
|
const lastUsed = Date.now();
|
||||||
await updateMap(cachedMap.id, { lastUsed });
|
await updateMap(cachedMap.id, { lastUsed });
|
||||||
@ -140,7 +146,12 @@ function NetworkedMapAndTokens({ session }) {
|
|||||||
}
|
}
|
||||||
} else if (asset.type === "token") {
|
} else if (asset.type === "token") {
|
||||||
const cachedToken = getToken(asset.id);
|
const cachedToken = getToken(asset.id);
|
||||||
if (cachedToken && cachedToken.lastModified >= asset.lastModified) {
|
if (cachedToken && cachedToken.lastModified === asset.lastModified) {
|
||||||
|
continue;
|
||||||
|
} else if (
|
||||||
|
cachedToken &&
|
||||||
|
cachedToken.lastModified > asset.lastModified
|
||||||
|
) {
|
||||||
// Update last used for cache invalidation
|
// Update last used for cache invalidation
|
||||||
const lastUsed = Date.now();
|
const lastUsed = Date.now();
|
||||||
await updateToken(cachedToken.id, { lastUsed });
|
await updateToken(cachedToken.id, { lastUsed });
|
||||||
@ -152,8 +163,16 @@ function NetworkedMapAndTokens({ session }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
requestAssetsIfNeeded();
|
requestAssetsIfNeeded();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
}, [
|
||||||
}, [assetManifest, partyState, session]);
|
assetManifest,
|
||||||
|
partyState,
|
||||||
|
session,
|
||||||
|
getMap,
|
||||||
|
getToken,
|
||||||
|
updateMap,
|
||||||
|
updateToken,
|
||||||
|
userId,
|
||||||
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map state
|
* Map state
|
||||||
@ -172,8 +191,7 @@ function NetworkedMapAndTokens({ session }) {
|
|||||||
) {
|
) {
|
||||||
updateMapState(debouncedMapState.mapId, debouncedMapState);
|
updateMapState(debouncedMapState.mapId, debouncedMapState);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
}, [currentMap, debouncedMapState, userId, database, updateMapState]);
|
||||||
}, [currentMap, debouncedMapState, userId, database]);
|
|
||||||
|
|
||||||
function handleMapChange(newMap, newMapState) {
|
function handleMapChange(newMap, newMapState) {
|
||||||
// Clear map before sending new one
|
// Clear map before sending new one
|
||||||
@ -402,10 +420,9 @@ function NetworkedMapAndTokens({ session }) {
|
|||||||
|
|
||||||
async function handleSocketMap(map) {
|
async function handleSocketMap(map) {
|
||||||
if (map) {
|
if (map) {
|
||||||
// If we're the owner get the full map from the database
|
if (map.type === "file") {
|
||||||
if (map.type === "file" && map.owner === userId) {
|
|
||||||
const fullMap = await getMapFromDB(map.id);
|
const fullMap = await getMapFromDB(map.id);
|
||||||
setCurrentMap(fullMap);
|
setCurrentMap(fullMap || map);
|
||||||
} else {
|
} else {
|
||||||
setCurrentMap(map);
|
setCurrentMap(map);
|
||||||
}
|
}
|
||||||
@ -428,19 +445,19 @@ function NetworkedMapAndTokens({ session }) {
|
|||||||
const canChangeMap = !isLoading;
|
const canChangeMap = !isLoading;
|
||||||
|
|
||||||
const canEditMapDrawing =
|
const canEditMapDrawing =
|
||||||
currentMap !== null &&
|
currentMap &&
|
||||||
currentMapState !== null &&
|
currentMapState &&
|
||||||
(currentMapState.editFlags.includes("drawing") ||
|
(currentMapState.editFlags.includes("drawing") ||
|
||||||
currentMap.owner === userId);
|
currentMap.owner === userId);
|
||||||
|
|
||||||
const canEditFogDrawing =
|
const canEditFogDrawing =
|
||||||
currentMap !== null &&
|
currentMap &&
|
||||||
currentMapState !== null &&
|
currentMapState &&
|
||||||
(currentMapState.editFlags.includes("fog") || currentMap.owner === userId);
|
(currentMapState.editFlags.includes("fog") || currentMap.owner === userId);
|
||||||
|
|
||||||
const canEditNotes =
|
const canEditNotes =
|
||||||
currentMap !== null &&
|
currentMap &&
|
||||||
currentMapState !== null &&
|
currentMapState &&
|
||||||
(currentMapState.editFlags.includes("notes") ||
|
(currentMapState.editFlags.includes("notes") ||
|
||||||
currentMap.owner === userId);
|
currentMap.owner === userId);
|
||||||
|
|
||||||
@ -448,8 +465,8 @@ function NetworkedMapAndTokens({ session }) {
|
|||||||
// If we have a map and state and have the token permission disabled
|
// If we have a map and state and have the token permission disabled
|
||||||
// and are not the map owner
|
// and are not the map owner
|
||||||
if (
|
if (
|
||||||
currentMapState !== null &&
|
currentMapState &&
|
||||||
currentMap !== null &&
|
currentMap &&
|
||||||
!currentMapState.editFlags.includes("tokens") &&
|
!currentMapState.editFlags.includes("tokens") &&
|
||||||
currentMap.owner !== userId
|
currentMap.owner !== userId
|
||||||
) {
|
) {
|
||||||
|
@ -4,13 +4,24 @@ import { getDatabase } from "../database";
|
|||||||
|
|
||||||
// Worker to load large amounts of database data on a separate thread
|
// Worker to load large amounts of database data on a separate thread
|
||||||
let obj = {
|
let obj = {
|
||||||
data: [],
|
data: null,
|
||||||
async loadData(table) {
|
/**
|
||||||
this.data = [];
|
* Load either a whole table or individual item from the DB
|
||||||
|
* @param {string} table Table to load from
|
||||||
|
* @param {string|undefined} key Optional database key to load, if undefined whole table will be loaded
|
||||||
|
*/
|
||||||
|
async loadData(table, key) {
|
||||||
try {
|
try {
|
||||||
let db = getDatabase({});
|
let db = getDatabase({});
|
||||||
// Use a cursor instead of toArray to prevent IPC max size error
|
if (key) {
|
||||||
await db.table(table).each((map) => this.data.push(map));
|
// Load specific item
|
||||||
|
this.data = await db.table(table).get(key);
|
||||||
|
} else {
|
||||||
|
// Load entire table
|
||||||
|
this.data = [];
|
||||||
|
// Use a cursor instead of toArray to prevent IPC max size error
|
||||||
|
await db.table(table).each((item) => this.data.push(item));
|
||||||
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user