2020-05-19 19:03:36 +10:00
|
|
|
import React, { useRef, useContext, useState } from "react";
|
2020-05-20 12:37:29 +10:00
|
|
|
import { Flex, Label, Button } from "theme-ui";
|
2020-05-19 19:03:36 +10:00
|
|
|
import shortid from "shortid";
|
2020-05-19 16:21:01 +10:00
|
|
|
|
|
|
|
|
import Modal from "../components/Modal";
|
|
|
|
|
import ImageDrop from "../components/ImageDrop";
|
|
|
|
|
import TokenTiles from "../components/token/TokenTiles";
|
2020-05-20 12:37:29 +10:00
|
|
|
import TokenSettings from "../components/token/TokenSettings";
|
2020-05-19 16:21:01 +10:00
|
|
|
|
2020-05-19 19:03:36 +10:00
|
|
|
import blobToBuffer from "../helpers/blobToBuffer";
|
|
|
|
|
|
2020-05-19 16:21:01 +10:00
|
|
|
import TokenDataContext from "../contexts/TokenDataContext";
|
2020-05-19 19:03:36 +10:00
|
|
|
import AuthContext from "../contexts/AuthContext";
|
2020-06-28 15:43:45 +10:00
|
|
|
import { isEmpty } from "../helpers/shared";
|
2020-05-19 16:21:01 +10:00
|
|
|
|
|
|
|
|
function SelectTokensModal({ isOpen, onRequestClose }) {
|
2020-05-19 19:03:36 +10:00
|
|
|
const { userId } = useContext(AuthContext);
|
2020-05-20 12:37:29 +10:00
|
|
|
const { ownedTokens, addToken, removeToken, updateToken } = useContext(
|
|
|
|
|
TokenDataContext
|
|
|
|
|
);
|
2020-05-19 16:21:01 +10:00
|
|
|
const fileInputRef = useRef();
|
|
|
|
|
|
2020-05-19 19:03:36 +10:00
|
|
|
const [imageLoading, setImageLoading] = useState(false);
|
|
|
|
|
|
|
|
|
|
const [selectedTokenId, setSelectedTokenId] = useState(null);
|
|
|
|
|
const selectedToken = ownedTokens.find(
|
|
|
|
|
(token) => token.id === selectedTokenId
|
|
|
|
|
);
|
|
|
|
|
|
2020-05-19 16:21:01 +10:00
|
|
|
function openImageDialog() {
|
|
|
|
|
if (fileInputRef.current) {
|
|
|
|
|
fileInputRef.current.click();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-19 19:03:36 +10:00
|
|
|
function handleTokenAdd(token) {
|
|
|
|
|
addToken(token);
|
2020-06-28 15:43:45 +10:00
|
|
|
setSelectedTokenId(token.id);
|
2020-05-19 19:03:36 +10:00
|
|
|
}
|
|
|
|
|
|
2020-05-31 10:53:33 +10:00
|
|
|
async function handleImagesUpload(files) {
|
|
|
|
|
for (let file of files) {
|
|
|
|
|
await handleImageUpload(file);
|
|
|
|
|
}
|
|
|
|
|
// Set file input to null to allow adding the same image 2 times in a row
|
|
|
|
|
fileInputRef.current.value = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleImageUpload(file) {
|
2020-05-19 19:03:36 +10:00
|
|
|
let name = "Unknown Map";
|
|
|
|
|
if (file.name) {
|
|
|
|
|
// Remove file extension
|
|
|
|
|
name = file.name.replace(/\.[^/.]+$/, "");
|
|
|
|
|
// Removed grid size expression
|
|
|
|
|
name = name.replace(/(\[ ?|\( ?)?\d+ ?(x|X) ?\d+( ?\]| ?\))?/, "");
|
|
|
|
|
// Clean string
|
|
|
|
|
name = name.replace(/ +/g, " ");
|
|
|
|
|
name = name.trim();
|
|
|
|
|
}
|
|
|
|
|
let image = new Image();
|
|
|
|
|
setImageLoading(true);
|
2020-05-31 10:53:33 +10:00
|
|
|
const buffer = await blobToBuffer(file);
|
|
|
|
|
|
|
|
|
|
// Copy file to avoid permissions issues
|
|
|
|
|
const blob = new Blob([buffer]);
|
|
|
|
|
// Create and load the image temporarily to get its dimensions
|
|
|
|
|
const url = URL.createObjectURL(blob);
|
|
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
2020-05-19 19:03:36 +10:00
|
|
|
image.onload = function () {
|
|
|
|
|
handleTokenAdd({
|
|
|
|
|
file: buffer,
|
|
|
|
|
name,
|
|
|
|
|
id: shortid.generate(),
|
2020-06-28 15:43:45 +10:00
|
|
|
type: "file",
|
2020-05-19 19:03:36 +10:00
|
|
|
created: Date.now(),
|
|
|
|
|
lastModified: Date.now(),
|
|
|
|
|
owner: userId,
|
2020-05-20 12:37:29 +10:00
|
|
|
defaultSize: 1,
|
2020-05-22 20:43:07 +10:00
|
|
|
isVehicle: false,
|
2020-05-28 16:23:20 +10:00
|
|
|
hideInSidebar: false,
|
2020-05-19 19:03:36 +10:00
|
|
|
});
|
2020-05-22 18:04:17 +10:00
|
|
|
setImageLoading(false);
|
2020-05-31 10:53:33 +10:00
|
|
|
resolve();
|
2020-05-19 19:03:36 +10:00
|
|
|
};
|
2020-05-31 10:53:33 +10:00
|
|
|
image.onerror = reject;
|
2020-05-19 19:03:36 +10:00
|
|
|
image.src = url;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-28 15:43:45 +10:00
|
|
|
async function handleTokenSelect(token) {
|
|
|
|
|
await applyTokenChanges();
|
2020-05-19 19:03:36 +10:00
|
|
|
setSelectedTokenId(token.id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleTokenRemove(id) {
|
|
|
|
|
await removeToken(id);
|
|
|
|
|
setSelectedTokenId(null);
|
|
|
|
|
}
|
2020-05-19 16:21:01 +10:00
|
|
|
|
2020-05-20 12:37:29 +10:00
|
|
|
/**
|
|
|
|
|
* Token settings
|
|
|
|
|
*/
|
|
|
|
|
const [showMoreSettings, setShowMoreSettings] = useState(false);
|
|
|
|
|
|
2020-06-28 15:43:45 +10:00
|
|
|
const [tokenSettingChanges, setTokenSettingChanges] = useState({});
|
|
|
|
|
|
|
|
|
|
function handleTokenSettingsChange(key, value) {
|
|
|
|
|
setTokenSettingChanges((prevChanges) => ({ ...prevChanges, [key]: value }));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function applyTokenChanges() {
|
|
|
|
|
if (selectedTokenId && !isEmpty(tokenSettingChanges)) {
|
|
|
|
|
await updateToken(selectedTokenId, tokenSettingChanges);
|
|
|
|
|
setTokenSettingChanges({});
|
|
|
|
|
}
|
2020-05-20 12:37:29 +10:00
|
|
|
}
|
|
|
|
|
|
2020-06-28 15:43:45 +10:00
|
|
|
async function handleRequestClose() {
|
|
|
|
|
await applyTokenChanges();
|
|
|
|
|
onRequestClose();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const selectedTokenWithChanges = { ...selectedToken, ...tokenSettingChanges };
|
|
|
|
|
|
2020-05-19 16:21:01 +10:00
|
|
|
return (
|
2020-06-28 15:43:45 +10:00
|
|
|
<Modal isOpen={isOpen} onRequestClose={handleRequestClose}>
|
2020-05-31 10:53:33 +10:00
|
|
|
<ImageDrop onDrop={handleImagesUpload} dropText="Drop token to upload">
|
2020-05-19 16:21:01 +10:00
|
|
|
<input
|
2020-05-31 10:53:33 +10:00
|
|
|
onChange={(event) => handleImagesUpload(event.target.files)}
|
2020-05-19 16:21:01 +10:00
|
|
|
type="file"
|
|
|
|
|
accept="image/*"
|
|
|
|
|
style={{ display: "none" }}
|
|
|
|
|
ref={fileInputRef}
|
2020-05-31 10:53:33 +10:00
|
|
|
multiple
|
2020-05-19 16:21:01 +10:00
|
|
|
/>
|
|
|
|
|
<Flex
|
|
|
|
|
sx={{
|
|
|
|
|
flexDirection: "column",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Label pt={2} pb={1}>
|
|
|
|
|
Edit or import a token
|
|
|
|
|
</Label>
|
2020-05-19 19:03:36 +10:00
|
|
|
<TokenTiles
|
|
|
|
|
tokens={ownedTokens}
|
|
|
|
|
onTokenAdd={openImageDialog}
|
2020-06-28 15:43:45 +10:00
|
|
|
selectedToken={selectedTokenWithChanges}
|
2020-05-19 19:03:36 +10:00
|
|
|
onTokenSelect={handleTokenSelect}
|
|
|
|
|
onTokenRemove={handleTokenRemove}
|
|
|
|
|
/>
|
2020-05-20 12:37:29 +10:00
|
|
|
<TokenSettings
|
2020-06-28 15:43:45 +10:00
|
|
|
token={selectedTokenWithChanges}
|
2020-05-20 12:37:29 +10:00
|
|
|
showMore={showMoreSettings}
|
|
|
|
|
onSettingsChange={handleTokenSettingsChange}
|
|
|
|
|
onShowMoreChange={setShowMoreSettings}
|
|
|
|
|
/>
|
|
|
|
|
<Button
|
|
|
|
|
variant="primary"
|
|
|
|
|
disabled={imageLoading}
|
2020-06-28 15:43:45 +10:00
|
|
|
onClick={handleRequestClose}
|
2020-05-20 12:37:29 +10:00
|
|
|
>
|
|
|
|
|
Done
|
|
|
|
|
</Button>
|
2020-05-19 16:21:01 +10:00
|
|
|
</Flex>
|
|
|
|
|
</ImageDrop>
|
|
|
|
|
</Modal>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default SelectTokensModal;
|