Moved add/remove maps/tokens to Observables to allow for cross session syncing

This commit is contained in:
Mitchell McCaffrey 2021-02-14 18:35:42 +11:00
parent 265472311e
commit cf9e428447
8 changed files with 97 additions and 34 deletions

View File

@ -19,6 +19,7 @@
"comlink": "^4.3.0",
"deep-diff": "^1.0.2",
"dexie": "^3.0.3",
"dexie-observable": "^3.0.0-beta.10",
"err-code": "^2.0.3",
"fake-indexeddb": "^3.1.2",
"file-saver": "^2.0.5",

View File

@ -112,6 +112,14 @@ export function MapDataProvider({ children }) {
[database]
);
const getMapStateFromDB = useCallback(
async (mapId) => {
let mapState = await database.table("states").get(mapId);
return mapState;
},
[database]
);
/**
* Keep up to cachedMapMax amount of maps that you don't own
* Sorted by when they we're last used
@ -140,11 +148,10 @@ export function MapDataProvider({ children }) {
*/
const addMap = useCallback(
async (map) => {
await database.table("maps").add(map);
// Just update map database as react state will be updated with an Observable
const state = { ...defaultMapState, mapId: map.id };
await database.table("maps").add(map);
await database.table("states").add(state);
setMaps((prevMaps) => [map, ...prevMaps]);
setMapStates((prevStates) => [state, ...prevStates]);
if (map.owner !== userId) {
await updateCache();
}
@ -156,14 +163,6 @@ export function MapDataProvider({ children }) {
async (id) => {
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]
);
@ -172,16 +171,6 @@ export function MapDataProvider({ children }) {
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]
);
@ -284,6 +273,46 @@ export function MapDataProvider({ children }) {
[database, updateCache, userId]
);
// Create DB observable to sync creating and deleting
useEffect(() => {
if (!database || databaseStatus === "loading") {
return;
}
function handleMapChanges(changes) {
for (let change of changes) {
if (change.table === "maps") {
if (change.type === 1) {
// Created
const map = change.obj;
const state = { ...defaultMapState, mapId: map.id };
setMaps((prevMaps) => [map, ...prevMaps]);
setMapStates((prevStates) => [state, ...prevStates]);
} else if (change.type === 3) {
// Deleted
const id = change.key;
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.on("changes", handleMapChanges);
return () => {
database.on("changes").unsubscribe(handleMapChanges);
};
}, [database, databaseStatus]);
const ownedMaps = maps.filter((map) => map.owner === userId);
const value = {
@ -301,6 +330,7 @@ export function MapDataProvider({ children }) {
getMap,
getMapFromDB,
mapsLoading,
getMapStateFromDB,
};
return (
<MapDataContext.Provider value={value}>{children}</MapDataContext.Provider>

View File

@ -115,7 +115,6 @@ export function TokenDataProvider({ children }) {
const addToken = useCallback(
async (token) => {
await database.table("tokens").add(token);
setTokens((prevTokens) => [token, ...prevTokens]);
if (token.owner !== userId) {
await updateCache();
}
@ -126,10 +125,6 @@ export function TokenDataProvider({ children }) {
const removeToken = useCallback(
async (id) => {
await database.table("tokens").delete(id);
setTokens((prevTokens) => {
const filtered = prevTokens.filter((token) => token.id !== id);
return filtered;
});
},
[database]
);
@ -137,10 +132,6 @@ export function TokenDataProvider({ children }) {
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]
);
@ -230,6 +221,38 @@ export function TokenDataProvider({ children }) {
});
}, []);
// Create DB observable to sync creating and deleting
useEffect(() => {
if (!database || databaseStatus === "loading") {
return;
}
function handleMapChanges(changes) {
for (let change of changes) {
if (change.table === "tokens") {
if (change.type === 1) {
// Created
const token = change.obj;
setTokens((prevTokens) => [token, ...prevTokens]);
} else if (change.type === 3) {
// Deleted
const id = change.key;
setTokens((prevTokens) => {
const filtered = prevTokens.filter((token) => token.id !== id);
return filtered;
});
}
}
}
}
database.on("changes", handleMapChanges);
return () => {
database.on("changes").unsubscribe(handleMapChanges);
};
}, [database, databaseStatus]);
const ownedTokens = tokens.filter((token) => token.owner === userId);
const tokensById = tokens.reduce((obj, token) => {

View File

@ -1,5 +1,6 @@
// eslint-disable-next-line no-unused-vars
import Dexie, { Version, DexieOptions } from "dexie";
import "dexie-observable";
import blobToBuffer from "./helpers/blobToBuffer";
import { getGridDefaultInset } from "./helpers/grid";
@ -391,9 +392,13 @@ const versions = {
});
});
},
// 1.8.0 - Upgrade for Dexie.Observable
21(v) {
v.stores({});
},
};
const latestVersion = 20;
const latestVersion = 21;
/**
* Load versions onto a database up to a specific version number

View File

@ -147,7 +147,7 @@ function EditMapModal({ isOpen, onDone, mapId }) {
<Label pt={2} pb={1}>
Edit map
</Label>
{isLoading ? (
{isLoading || !map ? (
<Flex
sx={{
width: "100%",

View File

@ -84,7 +84,7 @@ function EditTokenModal({ isOpen, onDone, tokenId }) {
<Label pt={2} pb={1}>
Edit token
</Label>
{isLoading ? (
{isLoading || !token ? (
<Flex
sx={{
width: "100%",

View File

@ -160,7 +160,6 @@ function ImportExportModal({ isOpen, onRequestClose }) {
db.close();
setIsLoading(false);
backgroundTaskRunningRef.current = false;
window.location.reload();
}
function exportSelectorFilter(table, value) {

View File

@ -4540,6 +4540,11 @@ detect-port-alt@1.1.6:
address "^1.0.1"
debug "^2.6.0"
dexie-observable@^3.0.0-beta.10:
version "3.0.0-beta.10"
resolved "https://registry.yarnpkg.com/dexie-observable/-/dexie-observable-3.0.0-beta.10.tgz#ad7a7e136defbb62f9eab9198a5cb9e10bce1c87"
integrity sha512-GMPwQMLh1nYqM1MYsOZudsIwSMqDMrAOBxNuw+Y2ijsrQTBPi3nRF2CinY02IdlmffkaU7DsDfnlgdaMEaiHTQ==
"dexie@^3.0.0-alpha.5 || ^2.0.4", dexie@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/dexie/-/dexie-3.0.3.tgz#ede63849dfe5f07e13e99bb72a040e8ac1d29dab"