Split tokens into data and state to avoid data duplication
This commit is contained in:
parent
65478d555b
commit
ece974c5d9
@ -21,8 +21,9 @@ const maxZoom = 5;
|
|||||||
function Map({
|
function Map({
|
||||||
map,
|
map,
|
||||||
mapState,
|
mapState,
|
||||||
onMapTokenChange,
|
tokens,
|
||||||
onMapTokenRemove,
|
onMapTokenStateChange,
|
||||||
|
onMapTokenStateRemove,
|
||||||
onMapChange,
|
onMapChange,
|
||||||
onMapStateChange,
|
onMapStateChange,
|
||||||
onMapDraw,
|
onMapDraw,
|
||||||
@ -31,13 +32,13 @@ function Map({
|
|||||||
}) {
|
}) {
|
||||||
const mapSource = useDataSource(map, defaultMapSources);
|
const mapSource = useDataSource(map, defaultMapSources);
|
||||||
|
|
||||||
function handleProxyDragEnd(isOnMap, token) {
|
function handleProxyDragEnd(isOnMap, tokenState) {
|
||||||
if (isOnMap && onMapTokenChange) {
|
if (isOnMap && onMapTokenStateChange) {
|
||||||
onMapTokenChange(token);
|
onMapTokenStateChange(tokenState);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isOnMap && onMapTokenRemove) {
|
if (!isOnMap && onMapTokenStateRemove) {
|
||||||
onMapTokenRemove(token);
|
onMapTokenStateRemove(tokenState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,10 +241,11 @@ function Map({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{mapState &&
|
{mapState &&
|
||||||
Object.values(mapState.tokens).map((token) => (
|
Object.values(mapState.tokens).map((tokenState) => (
|
||||||
<MapToken
|
<MapToken
|
||||||
key={token.id}
|
key={tokenState.id}
|
||||||
token={token}
|
token={tokens.find((token) => token.id === tokenState.tokenId)}
|
||||||
|
tokenState={tokenState}
|
||||||
tokenSizePercent={tokenSizePercent}
|
tokenSizePercent={tokenSizePercent}
|
||||||
className={`${mapTokenProxyClassName} ${mapTokenMenuClassName}`}
|
className={`${mapTokenProxyClassName} ${mapTokenMenuClassName}`}
|
||||||
/>
|
/>
|
||||||
@ -335,7 +337,7 @@ function Map({
|
|||||||
/>
|
/>
|
||||||
<TokenMenu
|
<TokenMenu
|
||||||
tokenClassName={mapTokenMenuClassName}
|
tokenClassName={mapTokenMenuClassName}
|
||||||
onTokenChange={onMapTokenChange}
|
onTokenChange={onMapTokenStateChange}
|
||||||
tokens={mapState && mapState.tokens}
|
tokens={mapState && mapState.tokens}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
@ -9,7 +9,7 @@ import useDataSource from "../../helpers/useDataSource";
|
|||||||
|
|
||||||
import { tokenSources } from "../../tokens";
|
import { tokenSources } from "../../tokens";
|
||||||
|
|
||||||
function MapToken({ token, tokenSizePercent, className }) {
|
function MapToken({ token, tokenState, tokenSizePercent, className }) {
|
||||||
const imageSource = useDataSource(token, tokenSources);
|
const imageSource = useDataSource(token, tokenSources);
|
||||||
|
|
||||||
const imageRef = useRef();
|
const imageRef = useRef();
|
||||||
@ -19,7 +19,7 @@ function MapToken({ token, tokenSizePercent, className }) {
|
|||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
transform: `translate(${token.x * 100}%, ${token.y * 100}%)`,
|
transform: `translate(${tokenState.x * 100}%, ${tokenState.y * 100}%)`,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
}}
|
}}
|
||||||
@ -30,7 +30,7 @@ function MapToken({ token, tokenSizePercent, className }) {
|
|||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
width: `${tokenSizePercent * (token.size || 1)}%`,
|
width: `${tokenSizePercent * (tokenState.size || 1)}%`,
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
@ -54,11 +54,13 @@ function MapToken({ token, tokenSizePercent, className }) {
|
|||||||
}}
|
}}
|
||||||
src={imageSource}
|
src={imageSource}
|
||||||
// pass id into the dom element which is then used by the ProxyToken
|
// pass id into the dom element which is then used by the ProxyToken
|
||||||
data-id={token.id}
|
data-id={tokenState.id}
|
||||||
ref={imageRef}
|
ref={imageRef}
|
||||||
/>
|
/>
|
||||||
{token.statuses && <TokenStatus statuses={token.statuses} />}
|
{tokenState.statuses && (
|
||||||
{token.label && <TokenLabel label={token.label} />}
|
<TokenStatus statuses={tokenState.statuses} />
|
||||||
|
)}
|
||||||
|
{tokenState.label && <TokenLabel label={tokenState.label} />}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState } from "react";
|
||||||
import { Box } from "theme-ui";
|
import { Box } from "theme-ui";
|
||||||
import shortid from "shortid";
|
import shortid from "shortid";
|
||||||
import SimpleBar from "simplebar-react";
|
import SimpleBar from "simplebar-react";
|
||||||
|
|
||||||
import { tokens as defaultTokens } from "../../tokens";
|
|
||||||
|
|
||||||
import ListToken from "./ListToken";
|
import ListToken from "./ListToken";
|
||||||
import ProxyToken from "./ProxyToken";
|
import ProxyToken from "./ProxyToken";
|
||||||
import NumberInput from "../NumberInput";
|
import NumberInput from "../NumberInput";
|
||||||
@ -13,27 +11,20 @@ import { fromEntries } from "../../helpers/shared";
|
|||||||
|
|
||||||
const listTokenClassName = "list-token";
|
const listTokenClassName = "list-token";
|
||||||
|
|
||||||
function Tokens({ onCreateMapToken }) {
|
function Tokens({ onCreateMapTokenState, tokens }) {
|
||||||
const [tokens, setTokens] = useState([]);
|
|
||||||
useEffect(() => {
|
|
||||||
const defaultTokensWithIds = [];
|
|
||||||
for (let defaultToken of defaultTokens) {
|
|
||||||
defaultTokensWithIds.push({ ...defaultToken, id: defaultToken.name });
|
|
||||||
}
|
|
||||||
setTokens(defaultTokensWithIds);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const [tokenSize, setTokenSize] = useState(1);
|
const [tokenSize, setTokenSize] = useState(1);
|
||||||
|
|
||||||
function handleProxyDragEnd(isOnMap, token) {
|
function handleProxyDragEnd(isOnMap, token) {
|
||||||
if (isOnMap && onCreateMapToken) {
|
if (isOnMap && onCreateMapTokenState) {
|
||||||
// Give the token an id
|
// Create a token state from the dragged token
|
||||||
onCreateMapToken({
|
onCreateMapTokenState({
|
||||||
...token,
|
|
||||||
id: shortid.generate(),
|
id: shortid.generate(),
|
||||||
|
tokenId: token.id,
|
||||||
size: tokenSize,
|
size: tokenSize,
|
||||||
label: "",
|
label: "",
|
||||||
statuses: [],
|
statuses: [],
|
||||||
|
x: token.x,
|
||||||
|
y: token.y,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@ import AuthModal from "../modals/AuthModal";
|
|||||||
|
|
||||||
import AuthContext from "../contexts/AuthContext";
|
import AuthContext from "../contexts/AuthContext";
|
||||||
|
|
||||||
|
import { tokens as defaultTokens } from "../tokens";
|
||||||
|
|
||||||
function Game() {
|
function Game() {
|
||||||
const { id: gameId } = useParams();
|
const { id: gameId } = useParams();
|
||||||
const { authenticationStatus, userId } = useContext(AuthContext);
|
const { authenticationStatus, userId } = useContext(AuthContext);
|
||||||
@ -70,7 +72,7 @@ function Game() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleMapTokenChange(token) {
|
async function handleMapTokenStateChange(token) {
|
||||||
if (mapState === null) {
|
if (mapState === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -83,18 +85,18 @@ function Game() {
|
|||||||
}));
|
}));
|
||||||
for (let peer of Object.values(peers)) {
|
for (let peer of Object.values(peers)) {
|
||||||
const data = { [token.id]: token };
|
const data = { [token.id]: token };
|
||||||
peer.connection.send({ id: "tokenEdit", data });
|
peer.connection.send({ id: "tokenStateEdit", data });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMapTokenRemove(token) {
|
function handleMapTokenStateRemove(token) {
|
||||||
setMapState((prevMapState) => {
|
setMapState((prevMapState) => {
|
||||||
const { [token.id]: old, ...rest } = prevMapState.tokens;
|
const { [token.id]: old, ...rest } = prevMapState.tokens;
|
||||||
return { ...prevMapState, tokens: rest };
|
return { ...prevMapState, tokens: rest };
|
||||||
});
|
});
|
||||||
for (let peer of Object.values(peers)) {
|
for (let peer of Object.values(peers)) {
|
||||||
const data = { [token.id]: token };
|
const data = { [token.id]: token };
|
||||||
peer.connection.send({ id: "tokenRemove", data });
|
peer.connection.send({ id: "tokenStateRemove", data });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,13 +198,13 @@ function Game() {
|
|||||||
if (data.id === "mapState") {
|
if (data.id === "mapState") {
|
||||||
setMapState(data.data);
|
setMapState(data.data);
|
||||||
}
|
}
|
||||||
if (data.id === "tokenEdit") {
|
if (data.id === "tokenStateEdit") {
|
||||||
setMapState((prevMapState) => ({
|
setMapState((prevMapState) => ({
|
||||||
...prevMapState,
|
...prevMapState,
|
||||||
tokens: { ...prevMapState.tokens, ...data.data },
|
tokens: { ...prevMapState.tokens, ...data.data },
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
if (data.id === "tokenRemove") {
|
if (data.id === "tokenStateRemove") {
|
||||||
setMapState((prevMapState) => ({
|
setMapState((prevMapState) => ({
|
||||||
...prevMapState,
|
...prevMapState,
|
||||||
tokens: omit(prevMapState.tokens, Object.keys(data.data)),
|
tokens: omit(prevMapState.tokens, Object.keys(data.data)),
|
||||||
@ -317,6 +319,21 @@ function Game() {
|
|||||||
}
|
}
|
||||||
}, [stream, peers, handleStreamEnd]);
|
}, [stream, peers, handleStreamEnd]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Token data
|
||||||
|
*/
|
||||||
|
const [tokens, setTokens] = useState([]);
|
||||||
|
useEffect(() => {
|
||||||
|
const defaultTokensWithIds = [];
|
||||||
|
for (let defaultToken of defaultTokens) {
|
||||||
|
defaultTokensWithIds.push({
|
||||||
|
...defaultToken,
|
||||||
|
id: `__default-${defaultToken.name}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setTokens(defaultTokensWithIds);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Flex sx={{ flexDirection: "column", height: "100%" }}>
|
<Flex sx={{ flexDirection: "column", height: "100%" }}>
|
||||||
@ -336,15 +353,19 @@ function Game() {
|
|||||||
<Map
|
<Map
|
||||||
map={map}
|
map={map}
|
||||||
mapState={mapState}
|
mapState={mapState}
|
||||||
onMapTokenChange={handleMapTokenChange}
|
tokens={tokens}
|
||||||
onMapTokenRemove={handleMapTokenRemove}
|
onMapTokenStateChange={handleMapTokenStateChange}
|
||||||
|
onMapTokenStateRemove={handleMapTokenStateRemove}
|
||||||
onMapChange={handleMapChange}
|
onMapChange={handleMapChange}
|
||||||
onMapStateChange={handleMapStateChange}
|
onMapStateChange={handleMapStateChange}
|
||||||
onMapDraw={handleMapDraw}
|
onMapDraw={handleMapDraw}
|
||||||
onMapDrawUndo={handleMapDrawUndo}
|
onMapDrawUndo={handleMapDrawUndo}
|
||||||
onMapDrawRedo={handleMapDrawRedo}
|
onMapDrawRedo={handleMapDrawRedo}
|
||||||
/>
|
/>
|
||||||
<Tokens onCreateMapToken={handleMapTokenChange} />
|
<Tokens
|
||||||
|
tokens={tokens}
|
||||||
|
onCreateMapTokenState={handleMapTokenStateChange}
|
||||||
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Banner isOpen={!!peerError} onRequestClose={() => setPeerError(null)}>
|
<Banner isOpen={!!peerError} onRequestClose={() => setPeerError(null)}>
|
||||||
|
Loading…
Reference in New Issue
Block a user