147 lines
4.3 KiB
JavaScript
147 lines
4.3 KiB
JavaScript
|
import React, { useEffect, useState, useContext } from "react";
|
||
|
|
||
|
import AuthContext from "./AuthContext";
|
||
|
import DatabaseContext from "./DatabaseContext";
|
||
|
|
||
|
import { maps as defaultMaps } from "../maps";
|
||
|
|
||
|
const MapDataContext = React.createContext();
|
||
|
|
||
|
const defaultMapState = {
|
||
|
tokens: {},
|
||
|
// An index into the draw actions array to which only actions before the
|
||
|
// index will be performed (used in undo and redo)
|
||
|
mapDrawActionIndex: -1,
|
||
|
mapDrawActions: [],
|
||
|
fogDrawActionIndex: -1,
|
||
|
fogDrawActions: [],
|
||
|
// Flags to determine what other people can edit
|
||
|
editFlags: ["drawing", "tokens"],
|
||
|
};
|
||
|
|
||
|
export function MapDataProvider({ children }) {
|
||
|
const { database } = useContext(DatabaseContext);
|
||
|
const { userId } = useContext(AuthContext);
|
||
|
|
||
|
const [maps, setMaps] = useState([]);
|
||
|
const [mapStates, setMapStates] = useState([]);
|
||
|
// Load maps from the database and ensure state is properly setup
|
||
|
useEffect(() => {
|
||
|
if (!userId || !database) {
|
||
|
return;
|
||
|
}
|
||
|
async function getDefaultMaps() {
|
||
|
const defaultMapsWithIds = [];
|
||
|
for (let i = 0; i < defaultMaps.length; i++) {
|
||
|
const defaultMap = defaultMaps[i];
|
||
|
const id = `__default-${defaultMap.name}`;
|
||
|
defaultMapsWithIds.push({
|
||
|
...defaultMap,
|
||
|
id,
|
||
|
owner: userId,
|
||
|
// Emulate the time increasing to avoid sort errors
|
||
|
created: Date.now() + i,
|
||
|
lastModified: Date.now() + i,
|
||
|
gridType: "grid",
|
||
|
});
|
||
|
// Add a state for the map if there isn't one already
|
||
|
const state = await database.table("states").get(id);
|
||
|
if (!state) {
|
||
|
await database.table("states").add({ ...defaultMapState, mapId: id });
|
||
|
}
|
||
|
}
|
||
|
return defaultMapsWithIds;
|
||
|
}
|
||
|
|
||
|
async function loadMaps() {
|
||
|
let storedMaps = await database
|
||
|
.table("maps")
|
||
|
.where({ owner: userId })
|
||
|
.toArray();
|
||
|
const sortedMaps = storedMaps.sort((a, b) => b.created - a.created);
|
||
|
const defaultMapsWithIds = await getDefaultMaps();
|
||
|
const allMaps = [...sortedMaps, ...defaultMapsWithIds];
|
||
|
setMaps(allMaps);
|
||
|
const storedStates = await database.table("states").toArray();
|
||
|
setMapStates(storedStates);
|
||
|
}
|
||
|
|
||
|
loadMaps();
|
||
|
}, [userId, database]);
|
||
|
|
||
|
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]);
|
||
|
}
|
||
|
|
||
|
async function removeMap(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;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
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) {
|
||
|
const change = { ...update, lastModified: Date.now() };
|
||
|
await database.table("maps").update(id, change);
|
||
|
setMaps((prevMaps) => {
|
||
|
const newMaps = [...prevMaps];
|
||
|
const i = newMaps.findIndex((map) => map.id === id);
|
||
|
if (i > -1) {
|
||
|
newMaps[i] = { ...newMaps[i], ...change };
|
||
|
}
|
||
|
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;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
const value = {
|
||
|
maps,
|
||
|
mapStates,
|
||
|
addMap,
|
||
|
removeMap,
|
||
|
resetMap,
|
||
|
updateMap,
|
||
|
updateMapState,
|
||
|
};
|
||
|
return (
|
||
|
<MapDataContext.Provider value={value}>{children}</MapDataContext.Provider>
|
||
|
);
|
||
|
}
|
||
|
|
||
|
export default MapDataContext;
|