Converted /modals to typescript
This commit is contained in:
@@ -1,9 +1,16 @@
|
||||
import React from "react";
|
||||
import { Box, Label, Text } from "theme-ui";
|
||||
|
||||
import Modal from "../components/Modal";
|
||||
|
||||
function AddPartyMemberModal({ isOpen, onRequestClose, gameId }) {
|
||||
function AddPartyMemberModal({
|
||||
isOpen,
|
||||
onRequestClose,
|
||||
gameId,
|
||||
}: {
|
||||
isOpen: boolean;
|
||||
onRequestClose: any;
|
||||
gameId: string;
|
||||
}) {
|
||||
return (
|
||||
<Modal isOpen={isOpen} onRequestClose={onRequestClose}>
|
||||
<Box>
|
||||
@@ -1,27 +1,27 @@
|
||||
import React, { useState, useRef } from "react";
|
||||
import { useState, useRef, ChangeEvent, FormEvent } from "react";
|
||||
import { Box, Input, Button, Label, Flex } from "theme-ui";
|
||||
|
||||
import { useAuth } from "../contexts/AuthContext";
|
||||
|
||||
import Modal from "../components/Modal";
|
||||
|
||||
function AuthModal({ isOpen, onSubmit }) {
|
||||
function AuthModal({ isOpen, onSubmit }: { isOpen: boolean, onSubmit: (newPassword: string) => void}) {
|
||||
const { password, setPassword } = useAuth();
|
||||
const [tmpPassword, setTempPassword] = useState(password);
|
||||
const [tmpPassword, setTempPassword] = useState<string>(password);
|
||||
|
||||
function handleChange(event) {
|
||||
setTempPassword(event.target.value);
|
||||
function handleChange(event: ChangeEvent<HTMLInputElement>): void {
|
||||
setTempPassword(event.target?.value);
|
||||
}
|
||||
|
||||
function handleSubmit(event) {
|
||||
function handleSubmit(event: FormEvent<HTMLElement>): void {
|
||||
event.preventDefault();
|
||||
setPassword(tmpPassword);
|
||||
onSubmit(tmpPassword);
|
||||
}
|
||||
|
||||
const inputRef = useRef();
|
||||
function focusInput() {
|
||||
inputRef.current && inputRef.current.focus();
|
||||
const inputRef = useRef<any>();
|
||||
function focusInput(): void {
|
||||
inputRef.current && inputRef.current?.focus();
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useRef } from "react";
|
||||
import { useRef } from "react";
|
||||
import { Box, Input, Button, Label, Flex } from "theme-ui";
|
||||
|
||||
import Modal from "../components/Modal";
|
||||
@@ -9,10 +9,16 @@ function ChangeNicknameModal({
|
||||
onChangeSubmit,
|
||||
nickname,
|
||||
onChange,
|
||||
}: {
|
||||
isOpen: boolean,
|
||||
onRequestClose: () => void,
|
||||
onChangeSubmit: any,
|
||||
nickname: string,
|
||||
onChange: any,
|
||||
}) {
|
||||
const inputRef = useRef();
|
||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||
function focusInput() {
|
||||
inputRef.current && inputRef.current.focus();
|
||||
inputRef.current && inputRef.current?.focus();
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -1,8 +1,16 @@
|
||||
import React from "react";
|
||||
import { Box, Label, Flex, Button, Text } from "theme-ui";
|
||||
|
||||
import Modal from "../components/Modal";
|
||||
|
||||
type ConfirmModalProps = {
|
||||
isOpen: boolean,
|
||||
onRequestClose: () => void,
|
||||
onConfirm: () => void,
|
||||
confirmText: string,
|
||||
label: string,
|
||||
description: string,
|
||||
}
|
||||
|
||||
function ConfirmModal({
|
||||
isOpen,
|
||||
onRequestClose,
|
||||
@@ -10,12 +18,12 @@ function ConfirmModal({
|
||||
confirmText,
|
||||
label,
|
||||
description,
|
||||
}) {
|
||||
}: ConfirmModalProps ) {
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onRequestClose={onRequestClose}
|
||||
style={{ maxWidth: "300px" }}
|
||||
style={{ content: { maxWidth: "300px" } }}
|
||||
>
|
||||
<Box>
|
||||
<Label py={2}>{label}</Label>
|
||||
@@ -1,24 +1,32 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Box, Button, Label, Flex } from "theme-ui";
|
||||
|
||||
import Modal from "../components/Modal";
|
||||
import Select from "../components/Select";
|
||||
|
||||
type EditGroupProps = {
|
||||
isOpen: boolean,
|
||||
onRequestClose: () => void,
|
||||
onChange: any,
|
||||
groups: string[],
|
||||
defaultGroup: string | undefined | false,
|
||||
}
|
||||
|
||||
function EditGroupModal({
|
||||
isOpen,
|
||||
onRequestClose,
|
||||
onChange,
|
||||
groups,
|
||||
defaultGroup,
|
||||
}) {
|
||||
const [value, setValue] = useState();
|
||||
const [options, setOptions] = useState([]);
|
||||
}: EditGroupProps) {
|
||||
const [value, setValue] = useState<{ value: string; label: string; } | undefined>();
|
||||
const [options, setOptions] = useState<{ value: string; label: string; }[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (defaultGroup) {
|
||||
setValue({ value: defaultGroup, label: defaultGroup });
|
||||
} else {
|
||||
setValue();
|
||||
setValue(undefined);
|
||||
}
|
||||
}, [defaultGroup]);
|
||||
|
||||
@@ -26,7 +34,7 @@ function EditGroupModal({
|
||||
setOptions(groups.map((group) => ({ value: group, label: group })));
|
||||
}, [groups]);
|
||||
|
||||
function handleCreate(group) {
|
||||
function handleCreate(group: string) {
|
||||
const newOption = { value: group, label: group };
|
||||
setValue(newOption);
|
||||
setOptions((prev) => [...prev, newOption]);
|
||||
@@ -40,7 +48,7 @@ function EditGroupModal({
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onRequestClose={onRequestClose}
|
||||
style={{ overflow: "visible" }}
|
||||
style={{ content: { overflow: "visible" } }}
|
||||
>
|
||||
<Box onSubmit={handleChange} sx={{ width: "300px" }}>
|
||||
<Label py={2}>Select or add a group</Label>
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Button, Flex, Label } from "theme-ui";
|
||||
|
||||
import Modal from "../components/Modal";
|
||||
@@ -12,8 +12,15 @@ import { isEmpty } from "../helpers/shared";
|
||||
import { getGridDefaultInset } from "../helpers/grid";
|
||||
|
||||
import useResponsiveLayout from "../hooks/useResponsiveLayout";
|
||||
import { MapState } from "../components/map/Map";
|
||||
|
||||
function EditMapModal({ isOpen, onDone, mapId }) {
|
||||
type EditMapProps = {
|
||||
isOpen: boolean,
|
||||
onDone: any,
|
||||
mapId: string
|
||||
}
|
||||
|
||||
function EditMapModal({ isOpen, onDone, mapId }: EditMapProps) {
|
||||
const {
|
||||
updateMap,
|
||||
updateMapState,
|
||||
@@ -23,8 +30,8 @@ function EditMapModal({ isOpen, onDone, mapId }) {
|
||||
} = useMapData();
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [map, setMap] = useState();
|
||||
const [mapState, setMapState] = useState();
|
||||
const [map, setMap] = useState<any>();
|
||||
const [mapState, setMapState] = useState<MapState>();
|
||||
// Load full map when modal is opened
|
||||
useEffect(() => {
|
||||
async function loadMap() {
|
||||
@@ -43,8 +50,8 @@ function EditMapModal({ isOpen, onDone, mapId }) {
|
||||
if (isOpen && mapId) {
|
||||
loadMap();
|
||||
} else {
|
||||
setMap();
|
||||
setMapState();
|
||||
setMap(undefined);
|
||||
setMapState(undefined);
|
||||
}
|
||||
}, [isOpen, mapId, getMapFromDB, getMapStateFromDB, getMap]);
|
||||
|
||||
@@ -64,19 +71,19 @@ function EditMapModal({ isOpen, onDone, mapId }) {
|
||||
*/
|
||||
// Local cache of map setting changes
|
||||
// Applied when done is clicked or map selection is changed
|
||||
const [mapSettingChanges, setMapSettingChanges] = useState({});
|
||||
const [mapStateSettingChanges, setMapStateSettingChanges] = useState({});
|
||||
const [mapSettingChanges, setMapSettingChanges] = useState<any>({});
|
||||
const [mapStateSettingChanges, setMapStateSettingChanges] = useState<any>({});
|
||||
|
||||
function handleMapSettingsChange(key, value) {
|
||||
setMapSettingChanges((prevChanges) => ({
|
||||
function handleMapSettingsChange(key: string, value: string) {
|
||||
setMapSettingChanges((prevChanges: any) => ({
|
||||
...prevChanges,
|
||||
[key]: value,
|
||||
lastModified: Date.now(),
|
||||
}));
|
||||
}
|
||||
|
||||
function handleMapStateSettingsChange(key, value) {
|
||||
setMapStateSettingChanges((prevChanges) => ({
|
||||
function handleMapStateSettingsChange(key: string, value: string) {
|
||||
setMapStateSettingChanges((prevChanges: any) => ({
|
||||
...prevChanges,
|
||||
[key]: value,
|
||||
}));
|
||||
@@ -137,7 +144,7 @@ function EditMapModal({ isOpen, onDone, mapId }) {
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onRequestClose={handleClose}
|
||||
style={{ maxWidth: layout.modalSize, width: "calc(100% - 16px)" }}
|
||||
style={{ content: {maxWidth: layout.modalSize, width: "calc(100% - 16px)"} }}
|
||||
>
|
||||
<Flex
|
||||
sx={{
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import { Button, Flex, Label } from "theme-ui";
|
||||
|
||||
import Modal from "../components/Modal";
|
||||
@@ -11,12 +11,19 @@ import { useTokenData } from "../contexts/TokenDataContext";
|
||||
import { isEmpty } from "../helpers/shared";
|
||||
|
||||
import useResponsiveLayout from "../hooks/useResponsiveLayout";
|
||||
import { Token } from "../tokens";
|
||||
|
||||
function EditTokenModal({ isOpen, onDone, tokenId }) {
|
||||
type EditModalProps = {
|
||||
isOpen: boolean,
|
||||
onDone: () => void,
|
||||
tokenId: string,
|
||||
};
|
||||
|
||||
function EditTokenModal({ isOpen, onDone, tokenId }: EditModalProps) {
|
||||
const { updateToken, getTokenFromDB } = useTokenData();
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [token, setToken] = useState();
|
||||
const [token, setToken] = useState<Token>();
|
||||
useEffect(() => {
|
||||
async function loadToken() {
|
||||
setIsLoading(true);
|
||||
@@ -27,7 +34,7 @@ function EditTokenModal({ isOpen, onDone, tokenId }) {
|
||||
if (isOpen && tokenId) {
|
||||
loadToken();
|
||||
} else {
|
||||
setToken();
|
||||
setToken(undefined);
|
||||
}
|
||||
}, [isOpen, tokenId, getTokenFromDB]);
|
||||
|
||||
@@ -41,10 +48,13 @@ function EditTokenModal({ isOpen, onDone, tokenId }) {
|
||||
onDone();
|
||||
}
|
||||
|
||||
const [tokenSettingChanges, setTokenSettingChanges] = useState({});
|
||||
const [tokenSettingChanges, setTokenSettingChanges] = useState<any>({});
|
||||
|
||||
function handleTokenSettingsChange(key, value) {
|
||||
setTokenSettingChanges((prevChanges) => ({ ...prevChanges, [key]: value }));
|
||||
function handleTokenSettingsChange(key: any, value: any) {
|
||||
setTokenSettingChanges((prevChanges: any) => ({
|
||||
...prevChanges,
|
||||
[key]: value,
|
||||
}));
|
||||
}
|
||||
|
||||
async function applyTokenChanges() {
|
||||
@@ -72,8 +82,7 @@ function EditTokenModal({ isOpen, onDone, tokenId }) {
|
||||
isOpen={isOpen}
|
||||
onRequestClose={handleClose}
|
||||
style={{
|
||||
maxWidth: layout.modalSize,
|
||||
width: "calc(100% - 16px)",
|
||||
content: { maxWidth: layout.modalSize, width: "calc(100% - 16px)" },
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
@@ -1,14 +1,13 @@
|
||||
import React from "react";
|
||||
import { Box, Label, Text } from "theme-ui";
|
||||
|
||||
import Modal from "../components/Modal";
|
||||
|
||||
function ForceUpdateModal({ isOpen }) {
|
||||
function ForceUpdateModal({ isOpen }: { isOpen: boolean }) {
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
allowClose={false}
|
||||
style={{ maxWidth: "450px" }}
|
||||
style={{ content: { maxWidth: "450px" } }}
|
||||
>
|
||||
<Box>
|
||||
<Label py={2}>New Update Available</Label>
|
||||
@@ -1,14 +1,13 @@
|
||||
import React from "react";
|
||||
import { Box, Label, Flex, Button, Text } from "theme-ui";
|
||||
|
||||
import Modal from "../components/Modal";
|
||||
|
||||
function GameExpiredModal({ isOpen, onRequestClose }) {
|
||||
function GameExpiredModal({ isOpen, onRequestClose }: { isOpen: boolean, onRequestClose: () => void }) {
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onRequestClose={onRequestClose}
|
||||
style={{ maxWidth: "450px" }}
|
||||
style={{ content: { maxWidth: "450px" } }}
|
||||
>
|
||||
<Box>
|
||||
<Label py={2}>Game Timed Out</Label>
|
||||
@@ -1,4 +1,3 @@
|
||||
import React from "react";
|
||||
import { Box, Label, Text } from "theme-ui";
|
||||
import raw from "raw.macro";
|
||||
|
||||
@@ -8,12 +7,12 @@ import Link from "../components/Link";
|
||||
|
||||
const gettingStarted = raw("../docs/howTo/gettingStarted.md");
|
||||
|
||||
function GettingStartedModal({ isOpen, onRequestClose }) {
|
||||
function GettingStartedModal({ isOpen, onRequestClose }: { isOpen: boolean, onRequestClose: () => void } ) {
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onRequestClose={onRequestClose}
|
||||
style={{ maxWidth: "450px" }}
|
||||
style={{ content: { maxWidth: "450px" } }}
|
||||
>
|
||||
<Box>
|
||||
<Label py={2}>Getting Started</Label>
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useRef, useState, useEffect } from "react";
|
||||
import { useRef, useState, useEffect } from "react";
|
||||
import { Box, Label, Text, Button, Flex } from "theme-ui";
|
||||
import { saveAs } from "file-saver";
|
||||
import * as Comlink from "comlink";
|
||||
@@ -16,24 +16,25 @@ import { useDatabase } from "../contexts/DatabaseContext";
|
||||
import SelectDataModal from "./SelectDataModal";
|
||||
|
||||
import { getDatabase } from "../database";
|
||||
import { Map, MapState, TokenState } from "../components/map/Map";
|
||||
|
||||
const importDBName = "OwlbearRodeoImportDB";
|
||||
|
||||
function ImportExportModal({ isOpen, onRequestClose }) {
|
||||
function ImportExportModal({ isOpen, onRequestClose }: { isOpen: boolean, onRequestClose: () => void}) {
|
||||
const { worker } = useDatabase();
|
||||
const { userId } = useAuth();
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState();
|
||||
const [error, setError] = useState<Error>();
|
||||
|
||||
const backgroundTaskRunningRef = useRef(false);
|
||||
const fileInputRef = useRef();
|
||||
const fileInputRef = useRef<any>();
|
||||
|
||||
const [showImportSelector, setShowImportSelector] = useState(false);
|
||||
const [showExportSelector, setShowExportSelector] = useState(false);
|
||||
|
||||
const { addToast } = useToasts();
|
||||
function addSuccessToast(message, maps, tokens) {
|
||||
function addSuccessToast(message: string, maps: any, tokens: TokenState[]) {
|
||||
const mapText = `${maps.length} map${maps.length > 1 ? "s" : ""}`;
|
||||
const tokenText = `${tokens.length} token${tokens.length > 1 ? "s" : ""}`;
|
||||
if (maps.length > 0 && tokens.length > 0) {
|
||||
@@ -53,11 +54,11 @@ function ImportExportModal({ isOpen, onRequestClose }) {
|
||||
|
||||
const loadingProgressRef = useRef(0);
|
||||
|
||||
function handleDBProgress({ completedRows, totalRows }) {
|
||||
function handleDBProgress({ completedRows, totalRows }: { completedRows: number, totalRows: number }) {
|
||||
loadingProgressRef.current = completedRows / totalRows;
|
||||
}
|
||||
|
||||
async function handleImportDatabase(file) {
|
||||
async function handleImportDatabase(file: File) {
|
||||
setIsLoading(true);
|
||||
backgroundTaskRunningRef.current = true;
|
||||
try {
|
||||
@@ -94,7 +95,7 @@ function ImportExportModal({ isOpen, onRequestClose }) {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
function handleBeforeUnload(event) {
|
||||
function handleBeforeUnload(event: any) {
|
||||
if (backgroundTaskRunningRef.current) {
|
||||
event.returnValue =
|
||||
"Database is still processing, are you sure you want to leave?";
|
||||
@@ -121,7 +122,7 @@ function ImportExportModal({ isOpen, onRequestClose }) {
|
||||
setShowImportSelector(false);
|
||||
}
|
||||
|
||||
async function handleImportSelectorConfirm(checkedMaps, checkedTokens) {
|
||||
async function handleImportSelectorConfirm(checkedMaps: any, checkedTokens: TokenState[]) {
|
||||
setIsLoading(true);
|
||||
backgroundTaskRunningRef.current = true;
|
||||
setShowImportSelector(false);
|
||||
@@ -131,11 +132,11 @@ function ImportExportModal({ isOpen, onRequestClose }) {
|
||||
const db = getDatabase({});
|
||||
try {
|
||||
// Keep track of a mapping of old token ids to new ones to apply them to the map states
|
||||
let newTokenIds = {};
|
||||
let newTokenIds: {[id: string]: string} = {};
|
||||
if (checkedTokens.length > 0) {
|
||||
const tokenIds = checkedTokens.map((token) => token.id);
|
||||
const tokensToAdd = await importDB.table("tokens").bulkGet(tokenIds);
|
||||
let newTokens = [];
|
||||
const tokensToAdd: TokenState[] = await importDB.table("tokens").bulkGet(tokenIds);
|
||||
let newTokens: TokenState[] = [];
|
||||
for (let token of tokensToAdd) {
|
||||
const newId = shortid.generate();
|
||||
newTokenIds[token.id] = newId;
|
||||
@@ -146,12 +147,12 @@ function ImportExportModal({ isOpen, onRequestClose }) {
|
||||
}
|
||||
|
||||
if (checkedMaps.length > 0) {
|
||||
const mapIds = checkedMaps.map((map) => map.id);
|
||||
const mapIds = checkedMaps.map((map: any) => map.id);
|
||||
const mapsToAdd = await importDB.table("maps").bulkGet(mapIds);
|
||||
let newMaps = [];
|
||||
let newStates = [];
|
||||
for (let map of mapsToAdd) {
|
||||
let state = await importDB.table("states").get(map.id);
|
||||
let state: MapState = await importDB.table("states").get(map.id);
|
||||
// Apply new token ids to imported state
|
||||
for (let tokenState of Object.values(state.tokens)) {
|
||||
if (tokenState.tokenId in newTokenIds) {
|
||||
@@ -179,7 +180,7 @@ function ImportExportModal({ isOpen, onRequestClose }) {
|
||||
backgroundTaskRunningRef.current = false;
|
||||
}
|
||||
|
||||
function exportSelectorFilter(table, value) {
|
||||
function exportSelectorFilter(table: any, value: Map | TokenState) {
|
||||
// Only show owned maps and tokens
|
||||
if (table === "maps" || table === "tokens") {
|
||||
if (value.owner === userId) {
|
||||
@@ -197,7 +198,7 @@ function ImportExportModal({ isOpen, onRequestClose }) {
|
||||
setShowExportSelector(false);
|
||||
}
|
||||
|
||||
async function handleExportSelectorConfirm(checkedMaps, checkedTokens) {
|
||||
async function handleExportSelectorConfirm(checkedMaps: Map[], checkedTokens: TokenState[]) {
|
||||
setShowExportSelector(false);
|
||||
setIsLoading(true);
|
||||
backgroundTaskRunningRef.current = true;
|
||||
@@ -238,7 +239,7 @@ function ImportExportModal({ isOpen, onRequestClose }) {
|
||||
Select import or export then select the data you wish to use
|
||||
</Text>
|
||||
<input
|
||||
onChange={(event) => handleImportDatabase(event.target.files[0])}
|
||||
onChange={(event) => event.target.files && handleImportDatabase(event.target.files[0])}
|
||||
type="file"
|
||||
accept=".owlbear"
|
||||
style={{ display: "none" }}
|
||||
@@ -272,7 +273,7 @@ function ImportExportModal({ isOpen, onRequestClose }) {
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
<ErrorBanner error={error} onRequestClose={() => setError()} />
|
||||
<ErrorBanner error={error} onRequestClose={() => setError(undefined)} />
|
||||
<SelectDataModal
|
||||
isOpen={showImportSelector}
|
||||
onRequestClose={handleImportSelectorClose}
|
||||
@@ -1,23 +1,23 @@
|
||||
import React, { useState, useRef } from "react";
|
||||
import { useState, useRef, FormEvent, ChangeEvent } from "react";
|
||||
import { Box, Label, Input, Button, Flex } from "theme-ui";
|
||||
import { useHistory } from "react-router-dom";
|
||||
|
||||
import Modal from "../components/Modal";
|
||||
|
||||
function JoinModal({ isOpen, onRequestClose }) {
|
||||
function JoinModal({ isOpen, onRequestClose }: any) {
|
||||
let history = useHistory();
|
||||
const [gameId, setGameId] = useState("");
|
||||
|
||||
function handleChange(event) {
|
||||
setGameId(event.target.value);
|
||||
function handleChange(event: ChangeEvent<HTMLInputElement>) {
|
||||
setGameId(event.target?.value);
|
||||
}
|
||||
|
||||
function handleSubmit(event) {
|
||||
function handleSubmit(event: FormEvent<HTMLDivElement>) {
|
||||
event.preventDefault();
|
||||
history.push(`/game/${gameId}`);
|
||||
}
|
||||
|
||||
const inputRef = useRef();
|
||||
const inputRef = useRef<any>();
|
||||
function focusInput() {
|
||||
inputRef.current && inputRef.current.focus();
|
||||
}
|
||||
@@ -27,6 +27,7 @@ function JoinModal({ isOpen, onRequestClose }) {
|
||||
isOpen={isOpen}
|
||||
onRequestClose={onRequestClose}
|
||||
onAfterOpen={focusInput}
|
||||
|
||||
>
|
||||
<Flex
|
||||
sx={{
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { ChangeEvent, useEffect, useState } from "react";
|
||||
import { Box, Label, Flex, Button, Text, Checkbox, Divider } from "theme-ui";
|
||||
import SimpleBar from "simplebar-react";
|
||||
|
||||
@@ -6,6 +6,15 @@ import Modal from "../components/Modal";
|
||||
import LoadingOverlay from "../components/LoadingOverlay";
|
||||
|
||||
import { getDatabase } from "../database";
|
||||
import { Props } from "react-modal";
|
||||
|
||||
type SelectDataProps = Props & {
|
||||
onConfirm: any,
|
||||
confirmText: string,
|
||||
label: string,
|
||||
databaseName: string,
|
||||
filter: any,
|
||||
}
|
||||
|
||||
function SelectDataModal({
|
||||
isOpen,
|
||||
@@ -15,10 +24,10 @@ function SelectDataModal({
|
||||
label,
|
||||
databaseName,
|
||||
filter,
|
||||
}) {
|
||||
const [maps, setMaps] = useState({});
|
||||
const [tokensByMap, setTokensByMap] = useState({});
|
||||
const [tokens, setTokens] = useState({});
|
||||
}: SelectDataProps) {
|
||||
const [maps, setMaps] = useState<any>({});
|
||||
const [tokensByMap, setTokensByMap] = useState<any>({});
|
||||
const [tokens, setTokens] = useState<any>({});
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const hasMaps = Object.values(maps).length > 0;
|
||||
@@ -29,9 +38,9 @@ function SelectDataModal({
|
||||
if (isOpen && databaseName) {
|
||||
setIsLoading(true);
|
||||
const db = getDatabase({ addons: [] }, databaseName);
|
||||
let loadedMaps = {};
|
||||
let loadedTokensByMap = {};
|
||||
let loadedTokens = {};
|
||||
let loadedMaps: any = [];
|
||||
let loadedTokensByMap: any = {};
|
||||
let loadedTokens: any = [];
|
||||
await db
|
||||
.table("maps")
|
||||
.filter((map) => filter("maps", map, map.id))
|
||||
@@ -44,7 +53,7 @@ function SelectDataModal({
|
||||
.each((state) => {
|
||||
loadedTokensByMap[state.mapId] = new Set(
|
||||
Object.values(state.tokens).map(
|
||||
(tokenState) => tokenState.tokenId
|
||||
(tokenState: any) => tokenState.tokenId
|
||||
)
|
||||
);
|
||||
});
|
||||
@@ -73,9 +82,9 @@ function SelectDataModal({
|
||||
}, [isOpen, databaseName, filter]);
|
||||
|
||||
// An object mapping a tokenId to how many checked maps it is currently used in
|
||||
const [tokenUsedCount, setTokenUsedCount] = useState({});
|
||||
const [tokenUsedCount, setTokenUsedCount] = useState<any>({});
|
||||
useEffect(() => {
|
||||
let tokensUsed = {};
|
||||
let tokensUsed: any = {};
|
||||
for (let mapId in maps) {
|
||||
if (maps[mapId].checked && mapId in tokensByMap) {
|
||||
for (let tokenId of tokensByMap[mapId]) {
|
||||
@@ -89,7 +98,7 @@ function SelectDataModal({
|
||||
}
|
||||
setTokenUsedCount(tokensUsed);
|
||||
// Update tokens to ensure used tokens are checked
|
||||
setTokens((prevTokens) => {
|
||||
setTokens((prevTokens: any) => {
|
||||
let newTokens = { ...prevTokens };
|
||||
for (let id in newTokens) {
|
||||
if (id in tokensUsed) {
|
||||
@@ -101,13 +110,13 @@ function SelectDataModal({
|
||||
}, [maps, tokensByMap]);
|
||||
|
||||
function handleConfirm() {
|
||||
let checkedMaps = Object.values(maps).filter((map) => map.checked);
|
||||
let checkedTokens = Object.values(tokens).filter((token) => token.checked);
|
||||
let checkedMaps = Object.values(maps).filter((map: any) => map.checked);
|
||||
let checkedTokens = Object.values(tokens).filter((token: any) => token.checked);
|
||||
onConfirm(checkedMaps, checkedTokens);
|
||||
}
|
||||
|
||||
function handleSelectMapsChanged(event) {
|
||||
setMaps((prevMaps) => {
|
||||
function handleSelectMapsChanged(event: ChangeEvent<HTMLInputElement>) {
|
||||
setMaps((prevMaps: any) => {
|
||||
let newMaps = { ...prevMaps };
|
||||
for (let id in newMaps) {
|
||||
newMaps[id].checked = event.target.checked;
|
||||
@@ -116,7 +125,7 @@ function SelectDataModal({
|
||||
});
|
||||
// If all token select is unchecked then ensure all tokens are unchecked
|
||||
if (!event.target.checked && !tokensSelectChecked) {
|
||||
setTokens((prevTokens) => {
|
||||
setTokens((prevTokens: any) => {
|
||||
let newTokens = { ...prevTokens };
|
||||
for (let id in newTokens) {
|
||||
newTokens[id].checked = false;
|
||||
@@ -126,14 +135,14 @@ function SelectDataModal({
|
||||
}
|
||||
}
|
||||
|
||||
function handleMapChange(event, map) {
|
||||
setMaps((prevMaps) => ({
|
||||
function handleMapChange(event: ChangeEvent<HTMLInputElement>, map: any) {
|
||||
setMaps((prevMaps: any) => ({
|
||||
...prevMaps,
|
||||
[map.id]: { ...map, checked: event.target.checked },
|
||||
}));
|
||||
// If all token select is unchecked then ensure tokens assosiated to this map are unchecked
|
||||
if (!event.target.checked && !tokensSelectChecked) {
|
||||
setTokens((prevTokens) => {
|
||||
setTokens((prevTokens: any) => {
|
||||
let newTokens = { ...prevTokens };
|
||||
for (let id in newTokens) {
|
||||
if (tokensByMap[map.id].has(id) && tokenUsedCount[id] === 1) {
|
||||
@@ -145,8 +154,8 @@ function SelectDataModal({
|
||||
}
|
||||
}
|
||||
|
||||
function handleSelectTokensChange(event) {
|
||||
setTokens((prevTokens) => {
|
||||
function handleSelectTokensChange(event: ChangeEvent<HTMLInputElement>) {
|
||||
setTokens((prevTokens: any) => {
|
||||
let newTokens = { ...prevTokens };
|
||||
for (let id in newTokens) {
|
||||
if (!(id in tokenUsedCount)) {
|
||||
@@ -157,8 +166,8 @@ function SelectDataModal({
|
||||
});
|
||||
}
|
||||
|
||||
function handleTokenChange(event, token) {
|
||||
setTokens((prevTokens) => ({
|
||||
function handleTokenChange(event: ChangeEvent<HTMLInputElement>, token: any) {
|
||||
setTokens((prevTokens: any) => ({
|
||||
...prevTokens,
|
||||
[token.id]: { ...token, checked: event.target.checked },
|
||||
}));
|
||||
@@ -167,14 +176,14 @@ function SelectDataModal({
|
||||
// Some tokens are checked not by maps or all tokens are checked by maps
|
||||
const tokensSelectChecked =
|
||||
Object.values(tokens).some(
|
||||
(token) => !(token.id in tokenUsedCount) && token.checked
|
||||
) || Object.values(tokens).every((token) => token.id in tokenUsedCount);
|
||||
(token: any) => !(token.id in tokenUsedCount) && token.checked
|
||||
) || Object.values(tokens).every((token: any) => token.id in tokenUsedCount);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onRequestClose={onRequestClose}
|
||||
style={{ maxWidth: "450px", width: "100%" }}
|
||||
style={{ content: {maxWidth: "450px", width: "100%"} }}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
@@ -205,13 +214,13 @@ function SelectDataModal({
|
||||
<Flex>
|
||||
<Label>
|
||||
<Checkbox
|
||||
checked={Object.values(maps).some((map) => map.checked)}
|
||||
checked={Object.values(maps).some((map: any) => map.checked)}
|
||||
onChange={handleSelectMapsChanged}
|
||||
/>
|
||||
Maps
|
||||
</Label>
|
||||
</Flex>
|
||||
{Object.values(maps).map((map) => (
|
||||
{Object.values(maps).map((map: any) => (
|
||||
<Label
|
||||
key={map.id}
|
||||
my={1}
|
||||
@@ -237,7 +246,7 @@ function SelectDataModal({
|
||||
/>
|
||||
Tokens
|
||||
</Label>
|
||||
{Object.values(tokens).map((token) => (
|
||||
{Object.values(tokens).map((token: any) => (
|
||||
<Box pl={4} my={1} key={token.id}>
|
||||
<Label sx={{ fontFamily: "body2" }}>
|
||||
<Checkbox
|
||||
@@ -265,8 +274,8 @@ function SelectDataModal({
|
||||
</Button>
|
||||
<Button
|
||||
disabled={
|
||||
!Object.values(maps).some((map) => map.checked) &&
|
||||
!Object.values(tokens).some((token) => token.checked)
|
||||
!Object.values(maps).some((map: any) => map.checked) &&
|
||||
!Object.values(tokens).some((token: any) => token.checked)
|
||||
}
|
||||
sx={{ flexGrow: 1 }}
|
||||
m={1}
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { Flex, Label, Button } from "theme-ui";
|
||||
|
||||
import Modal from "../components/Modal";
|
||||
@@ -7,8 +7,16 @@ import DiceTiles from "../components/dice/DiceTiles";
|
||||
import { dice } from "../dice";
|
||||
|
||||
import useResponsiveLayout from "../hooks/useResponsiveLayout";
|
||||
import Dice from "../dice/Dice";
|
||||
|
||||
function SelectDiceModal({ isOpen, onRequestClose, onDone, defaultDice }) {
|
||||
type SelectDiceProps = {
|
||||
isOpen: boolean,
|
||||
onRequestClose: () => void,
|
||||
onDone: any,
|
||||
defaultDice: Dice
|
||||
}
|
||||
|
||||
function SelectDiceModal({ isOpen, onRequestClose, onDone, defaultDice }: SelectDiceProps) {
|
||||
const [selectedDice, setSelectedDice] = useState(defaultDice);
|
||||
const layout = useResponsiveLayout();
|
||||
|
||||
@@ -16,7 +24,7 @@ function SelectDiceModal({ isOpen, onRequestClose, onDone, defaultDice }) {
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onRequestClose={onRequestClose}
|
||||
style={{ maxWidth: layout.modalSize, width: "calc(100% - 16px)" }}
|
||||
style={{ content: { maxWidth: layout.modalSize, width: "calc(100% - 16px)" } }}
|
||||
>
|
||||
<Flex
|
||||
sx={{
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useRef, useState } from "react";
|
||||
import { ChangeEvent, useRef, useState } from "react";
|
||||
import { Button, Flex, Label } from "theme-ui";
|
||||
import shortid from "shortid";
|
||||
import Case from "case";
|
||||
@@ -30,6 +30,15 @@ import { useAuth } from "../contexts/AuthContext";
|
||||
import { useKeyboard, useBlur } from "../contexts/KeyboardContext";
|
||||
|
||||
import shortcuts from "../shortcuts";
|
||||
import { MapState } from "../components/map/Map";
|
||||
|
||||
type SelectMapProps = {
|
||||
isOpen: boolean,
|
||||
onDone: any,
|
||||
onMapChange: any,
|
||||
onMapReset: any,
|
||||
currentMap: any
|
||||
}
|
||||
|
||||
const defaultMapProps = {
|
||||
showGrid: false,
|
||||
@@ -56,7 +65,7 @@ function SelectMapModal({
|
||||
onMapReset,
|
||||
// The map currently being view in the map screen
|
||||
currentMap,
|
||||
}) {
|
||||
}: SelectMapProps ) {
|
||||
const { addToast } = useToasts();
|
||||
|
||||
const { userId } = useAuth();
|
||||
@@ -79,7 +88,7 @@ function SelectMapModal({
|
||||
const [search, setSearch] = useState("");
|
||||
const [filteredMaps, filteredMapScores] = useSearch(ownedMaps, search);
|
||||
|
||||
function handleSearchChange(event) {
|
||||
function handleSearchChange(event: ChangeEvent<HTMLInputElement>) {
|
||||
setSearch(event.target.value);
|
||||
}
|
||||
|
||||
@@ -88,7 +97,7 @@ function SelectMapModal({
|
||||
*/
|
||||
const [isGroupModalOpen, setIsGroupModalOpen] = useState(false);
|
||||
|
||||
async function handleMapsGroup(group) {
|
||||
async function handleMapsGroup(group: any) {
|
||||
setIsLoading(true);
|
||||
setIsGroupModalOpen(false);
|
||||
await updateMaps(selectedMapIds, { group });
|
||||
@@ -106,15 +115,15 @@ function SelectMapModal({
|
||||
* Image Upload
|
||||
*/
|
||||
|
||||
const fileInputRef = useRef();
|
||||
const fileInputRef = useRef<any>();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const [isLargeImageWarningModalOpen, setShowLargeImageWarning] = useState(
|
||||
false
|
||||
);
|
||||
const largeImageWarningFiles = useRef();
|
||||
const largeImageWarningFiles = useRef<any>();
|
||||
|
||||
async function handleImagesUpload(files) {
|
||||
async function handleImagesUpload(files: any) {
|
||||
if (navigator.storage) {
|
||||
// Attempt to enable persistant storage
|
||||
await navigator.storage.persist();
|
||||
@@ -166,7 +175,7 @@ function SelectMapModal({
|
||||
clearFileInput();
|
||||
}
|
||||
|
||||
async function handleImageUpload(file) {
|
||||
async function handleImageUpload(file: any) {
|
||||
if (!file) {
|
||||
return Promise.reject();
|
||||
}
|
||||
@@ -222,9 +231,9 @@ function SelectMapModal({
|
||||
}
|
||||
|
||||
// Create resolutions
|
||||
const resolutions = {};
|
||||
const resolutions: any = {};
|
||||
for (let resolution of mapResolutions) {
|
||||
const resolutionPixelSize = Vector2.multiply(
|
||||
const resolutionPixelSize: Vector2 = Vector2.multiply(
|
||||
gridSize,
|
||||
resolution.size
|
||||
);
|
||||
@@ -234,7 +243,7 @@ function SelectMapModal({
|
||||
) {
|
||||
const resized = await resizeImage(
|
||||
image,
|
||||
Vector2.max(resolutionPixelSize),
|
||||
Vector2.max(resolutionPixelSize, undefined) as number,
|
||||
file.type,
|
||||
resolution.quality
|
||||
);
|
||||
@@ -284,7 +293,7 @@ function SelectMapModal({
|
||||
});
|
||||
setIsLoading(false);
|
||||
URL.revokeObjectURL(url);
|
||||
resolve();
|
||||
resolve(undefined);
|
||||
};
|
||||
image.onerror = reject;
|
||||
image.src = url;
|
||||
@@ -293,7 +302,7 @@ function SelectMapModal({
|
||||
|
||||
function openImageDialog() {
|
||||
if (fileInputRef.current) {
|
||||
fileInputRef.current.click();
|
||||
fileInputRef.current?.click();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,16 +311,16 @@ function SelectMapModal({
|
||||
*/
|
||||
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
|
||||
// The map selected in the modal
|
||||
const [selectedMapIds, setSelectedMapIds] = useState([]);
|
||||
const [selectedMapIds, setSelectedMapIds] = useState<string[]>([]);
|
||||
|
||||
const selectedMaps = ownedMaps.filter((map) =>
|
||||
const selectedMaps = ownedMaps.filter((map: any) =>
|
||||
selectedMapIds.includes(map.id)
|
||||
);
|
||||
const selectedMapStates = mapStates.filter((state) =>
|
||||
const selectedMapStates = mapStates.filter((state: MapState) =>
|
||||
selectedMapIds.includes(state.mapId)
|
||||
);
|
||||
|
||||
async function handleMapAdd(map) {
|
||||
async function handleMapAdd(map: any) {
|
||||
await addMap(map);
|
||||
setSelectedMapIds([map.id]);
|
||||
}
|
||||
@@ -346,7 +355,7 @@ function SelectMapModal({
|
||||
// Either single, multiple or range
|
||||
const [selectMode, setSelectMode] = useState("single");
|
||||
|
||||
function handleMapSelect(map) {
|
||||
function handleMapSelect(map: any) {
|
||||
handleItemSelect(
|
||||
map,
|
||||
selectMode,
|
||||
@@ -392,7 +401,7 @@ function SelectMapModal({
|
||||
/**
|
||||
* Shortcuts
|
||||
*/
|
||||
function handleKeyDown(event) {
|
||||
function handleKeyDown(event: KeyboardEvent): KeyboardEvent | void {
|
||||
if (!isOpen) {
|
||||
return;
|
||||
}
|
||||
@@ -406,7 +415,7 @@ function SelectMapModal({
|
||||
// Selected maps and none are default
|
||||
if (
|
||||
selectedMapIds.length > 0 &&
|
||||
!selectedMaps.some((map) => map.type === "default")
|
||||
!selectedMaps.some((map: any) => map.type === "default")
|
||||
) {
|
||||
// Ensure all other modals are closed
|
||||
setIsGroupModalOpen(false);
|
||||
@@ -417,7 +426,7 @@ function SelectMapModal({
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeyUp(event) {
|
||||
function handleKeyUp(event: KeyboardEvent) {
|
||||
if (!isOpen) {
|
||||
return;
|
||||
}
|
||||
@@ -444,7 +453,7 @@ function SelectMapModal({
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onRequestClose={handleClose}
|
||||
style={{ maxWidth: layout.modalSize, width: "calc(100% - 16px)" }}
|
||||
style={{ content: { maxWidth: layout.modalSize, width: "calc(100% - 16px)" } }}
|
||||
>
|
||||
<ImageDrop onDrop={handleImagesUpload} dropText="Drop map to upload">
|
||||
<input
|
||||
@@ -500,15 +509,15 @@ function SelectMapModal({
|
||||
isOpen={isGroupModalOpen}
|
||||
onChange={handleMapsGroup}
|
||||
groups={mapGroups.filter(
|
||||
(group) => group !== "" && group !== "default"
|
||||
(group: any) => group !== "" && group !== "default"
|
||||
)}
|
||||
onRequestClose={() => setIsGroupModalOpen(false)}
|
||||
// Select the default group by testing whether all selected maps are the same
|
||||
defaultGroup={
|
||||
selectedMaps.length > 0 &&
|
||||
selectedMaps
|
||||
.map((map) => map.group)
|
||||
.reduce((prev, curr) => (prev === curr ? curr : undefined))
|
||||
.map((map: any) => map.group)
|
||||
.reduce((prev: any, curr: any) => (prev === curr ? curr : undefined))
|
||||
}
|
||||
/>
|
||||
<ConfirmModal
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useRef, useState } from "react";
|
||||
import { ChangeEvent, useRef, useState } from "react";
|
||||
import { Flex, Label, Button } from "theme-ui";
|
||||
import shortid from "shortid";
|
||||
import Case from "case";
|
||||
@@ -24,8 +24,9 @@ import { useAuth } from "../contexts/AuthContext";
|
||||
import { useKeyboard, useBlur } from "../contexts/KeyboardContext";
|
||||
|
||||
import shortcuts from "../shortcuts";
|
||||
import { FileToken, Token } from "../tokens";
|
||||
|
||||
function SelectTokensModal({ isOpen, onRequestClose }) {
|
||||
function SelectTokensModal({ isOpen, onRequestClose }: { isOpen: boolean, onRequestClose: any }) {
|
||||
const { addToast } = useToasts();
|
||||
|
||||
const { userId } = useAuth();
|
||||
@@ -43,7 +44,7 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
|
||||
const [search, setSearch] = useState("");
|
||||
const [filteredTokens, filteredTokenScores] = useSearch(ownedTokens, search);
|
||||
|
||||
function handleSearchChange(event) {
|
||||
function handleSearchChange(event: ChangeEvent<HTMLInputElement>) {
|
||||
setSearch(event.target.value);
|
||||
}
|
||||
|
||||
@@ -52,7 +53,7 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
|
||||
*/
|
||||
const [isGroupModalOpen, setIsGroupModalOpen] = useState(false);
|
||||
|
||||
async function handleTokensGroup(group) {
|
||||
async function handleTokensGroup(group: string) {
|
||||
setIsLoading(true);
|
||||
setIsGroupModalOpen(false);
|
||||
await updateTokens(selectedTokenIds, { group });
|
||||
@@ -70,13 +71,13 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
|
||||
* Image Upload
|
||||
*/
|
||||
|
||||
const fileInputRef = useRef();
|
||||
const fileInputRef = useRef<any>();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const [isLargeImageWarningModalOpen, setShowLargeImageWarning] = useState(
|
||||
false
|
||||
);
|
||||
const largeImageWarningFiles = useRef();
|
||||
const largeImageWarningFiles = useRef<File[]>();
|
||||
|
||||
function openImageDialog() {
|
||||
if (fileInputRef.current) {
|
||||
@@ -84,12 +85,17 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleImagesUpload(files) {
|
||||
async function handleImagesUpload(files: FileList | null) {
|
||||
if (navigator.storage) {
|
||||
// Attempt to enable persistant storage
|
||||
await navigator.storage.persist();
|
||||
}
|
||||
|
||||
// TODO: handle null files
|
||||
if (files === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
let tokenFiles = [];
|
||||
for (let file of files) {
|
||||
if (file.size > 5e7) {
|
||||
@@ -129,6 +135,9 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
|
||||
async function handleLargeImageWarningConfirm() {
|
||||
setShowLargeImageWarning(false);
|
||||
const files = largeImageWarningFiles.current;
|
||||
if (!files) {
|
||||
return;
|
||||
}
|
||||
for (let file of files) {
|
||||
await handleImageUpload(file);
|
||||
}
|
||||
@@ -136,7 +145,7 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
|
||||
clearFileInput();
|
||||
}
|
||||
|
||||
async function handleImageUpload(file) {
|
||||
async function handleImageUpload(file: File) {
|
||||
let name = "Unknown Token";
|
||||
if (file.name) {
|
||||
// Remove file extension
|
||||
@@ -180,7 +189,7 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
|
||||
height: image.height,
|
||||
});
|
||||
setIsLoading(false);
|
||||
resolve();
|
||||
resolve(undefined);
|
||||
};
|
||||
image.onerror = reject;
|
||||
image.src = url;
|
||||
@@ -190,13 +199,13 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
|
||||
/**
|
||||
* Token controls
|
||||
*/
|
||||
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
|
||||
const [selectedTokenIds, setSelectedTokenIds] = useState([]);
|
||||
const [isEditModalOpen, setIsEditModalOpen] = useState<boolean>(false);
|
||||
const [selectedTokenIds, setSelectedTokenIds] = useState<string[]>([]);
|
||||
const selectedTokens = ownedTokens.filter((token) =>
|
||||
selectedTokenIds.includes(token.id)
|
||||
);
|
||||
|
||||
function handleTokenAdd(token) {
|
||||
function handleTokenAdd(token: FileToken) {
|
||||
addToken(token);
|
||||
setSelectedTokenIds([token.id]);
|
||||
}
|
||||
@@ -210,7 +219,7 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
||||
async function handleTokensHide(hideInSidebar) {
|
||||
async function handleTokensHide(hideInSidebar: boolean) {
|
||||
setIsLoading(true);
|
||||
await updateTokens(selectedTokenIds, { hideInSidebar });
|
||||
setIsLoading(false);
|
||||
@@ -219,7 +228,7 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
|
||||
// Either single, multiple or range
|
||||
const [selectMode, setSelectMode] = useState("single");
|
||||
|
||||
async function handleTokenSelect(token) {
|
||||
async function handleTokenSelect(token: Token) {
|
||||
handleItemSelect(
|
||||
token,
|
||||
selectMode,
|
||||
@@ -233,7 +242,7 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
|
||||
/**
|
||||
* Shortcuts
|
||||
*/
|
||||
function handleKeyDown(event) {
|
||||
function handleKeyDown(event: KeyboardEvent) {
|
||||
if (!isOpen) {
|
||||
return;
|
||||
}
|
||||
@@ -257,7 +266,7 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeyUp(event) {
|
||||
function handleKeyUp(event: KeyboardEvent) {
|
||||
if (!isOpen) {
|
||||
return;
|
||||
}
|
||||
@@ -280,11 +289,19 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
|
||||
|
||||
const layout = useResponsiveLayout();
|
||||
|
||||
let tokenId;
|
||||
if (selectedTokens.length === 1 && selectedTokens[0].id) {
|
||||
tokenId = selectedTokens[0].id
|
||||
} else {
|
||||
// TODO: handle tokenId not found
|
||||
tokenId = ""
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onRequestClose={onRequestClose}
|
||||
style={{ maxWidth: layout.modalSize, width: "calc(100% - 16px)" }}
|
||||
style={{ content: { maxWidth: layout.modalSize, width: "calc(100% - 16px)" } }}
|
||||
>
|
||||
<ImageDrop onDrop={handleImagesUpload} dropText="Drop token to upload">
|
||||
<input
|
||||
@@ -328,17 +345,19 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
|
||||
</Button>
|
||||
</Flex>
|
||||
</ImageDrop>
|
||||
<>
|
||||
{(isLoading || tokensLoading) && <LoadingOverlay bg="overlay" />}
|
||||
</>
|
||||
<EditTokenModal
|
||||
isOpen={isEditModalOpen}
|
||||
onDone={() => setIsEditModalOpen(false)}
|
||||
tokenId={selectedTokens.length === 1 && selectedTokens[0].id}
|
||||
tokenId={tokenId}
|
||||
/>
|
||||
<EditGroupModal
|
||||
isOpen={isGroupModalOpen}
|
||||
onChange={handleTokensGroup}
|
||||
groups={tokenGroups.filter(
|
||||
(group) => group !== "" && group !== "default"
|
||||
(group: string) => group !== "" && group !== "default"
|
||||
)}
|
||||
onRequestClose={() => setIsGroupModalOpen(false)}
|
||||
// Select the default group by testing whether all selected tokens are the same
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import {
|
||||
Label,
|
||||
Flex,
|
||||
@@ -21,8 +21,9 @@ import useSetting from "../hooks/useSetting";
|
||||
|
||||
import ConfirmModal from "./ConfirmModal";
|
||||
import ImportExportModal from "./ImportExportModal";
|
||||
import { MapState } from "../components/map/Map";
|
||||
|
||||
function SettingsModal({ isOpen, onRequestClose }) {
|
||||
function SettingsModal({ isOpen, onRequestClose }: { isOpen: boolean, onRequestClose: () => void }) {
|
||||
const { database, databaseStatus } = useDatabase();
|
||||
const { userId } = useAuth();
|
||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||
@@ -32,7 +33,7 @@ function SettingsModal({ isOpen, onRequestClose }) {
|
||||
);
|
||||
const [showFogGuides, setShowFogGuides] = useSetting("fog.showGuides");
|
||||
const [fogEditOpacity, setFogEditOpacity] = useSetting("fog.editOpacity");
|
||||
const [storageEstimate, setStorageEstimate] = useState();
|
||||
const [storageEstimate, setStorageEstimate] = useState<StorageEstimate>();
|
||||
const [isImportExportModalOpen, setIsImportExportModalOpen] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
@@ -58,7 +59,7 @@ function SettingsModal({ isOpen, onRequestClose }) {
|
||||
async function handleEraseAllData() {
|
||||
setIsLoading(true);
|
||||
localStorage.clear();
|
||||
await database.delete();
|
||||
await database?.delete();
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
@@ -66,6 +67,11 @@ function SettingsModal({ isOpen, onRequestClose }) {
|
||||
setIsLoading(true);
|
||||
// Clear saved settings
|
||||
localStorage.clear();
|
||||
|
||||
//TODO: handle id database is undefined
|
||||
if (!database) {
|
||||
return;
|
||||
}
|
||||
// Clear map cache
|
||||
await database.table("maps").where("owner").notEqual(userId).delete();
|
||||
// Find all other peoples tokens who aren't benig used in a map state and delete them
|
||||
@@ -74,7 +80,7 @@ function SettingsModal({ isOpen, onRequestClose }) {
|
||||
.where("owner")
|
||||
.notEqual(userId)
|
||||
.toArray();
|
||||
const states = await database.table("states").toArray();
|
||||
const states: MapState[] = await database?.table("states").toArray();
|
||||
for (let token of tokens) {
|
||||
let inUse = false;
|
||||
for (let state of states) {
|
||||
@@ -126,7 +132,7 @@ function SettingsModal({ isOpen, onRequestClose }) {
|
||||
sx={{ width: "initial" }}
|
||||
value={fogEditOpacity}
|
||||
onChange={(e) => setFogEditOpacity(parseFloat(e.target.value))}
|
||||
labelFunc={(value) => `${Math.round(value * 100)}%`}
|
||||
labelFunc={(value: number) => `${Math.round(value * 100)}%`}
|
||||
/>
|
||||
</Label>
|
||||
<Label py={2}>
|
||||
@@ -139,7 +145,7 @@ function SettingsModal({ isOpen, onRequestClose }) {
|
||||
sx={{ width: "initial" }}
|
||||
value={labelSize}
|
||||
onChange={(e) => setLabelSize(parseFloat(e.target.value))}
|
||||
labelFunc={(value) => `${value}x`}
|
||||
labelFunc={(value: number) => `${value}x`}
|
||||
/>
|
||||
</Label>
|
||||
<Label py={2}>
|
||||
@@ -154,7 +160,7 @@ function SettingsModal({ isOpen, onRequestClose }) {
|
||||
onChange={(e) =>
|
||||
setGridSnappingSensitivity(parseFloat(e.target.value))
|
||||
}
|
||||
labelFunc={(value) => `${value * 2}`}
|
||||
labelFunc={(value: number) => `${value * 2}`}
|
||||
/>
|
||||
</Label>
|
||||
<Divider bg="text" />
|
||||
@@ -185,13 +191,13 @@ function SettingsModal({ isOpen, onRequestClose }) {
|
||||
Import / Export Data
|
||||
</Button>
|
||||
</Flex>
|
||||
{storageEstimate && (
|
||||
{storageEstimate !&& (
|
||||
<Flex sx={{ justifyContent: "center" }}>
|
||||
<Text variant="caption">
|
||||
Storage Used: {prettyBytes(storageEstimate.usage)} of{" "}
|
||||
{prettyBytes(storageEstimate.quota)} (
|
||||
Storage Used: {prettyBytes(storageEstimate.usage as number)} of{" "}
|
||||
{prettyBytes(storageEstimate.quota as number)} (
|
||||
{Math.round(
|
||||
(storageEstimate.usage / Math.max(storageEstimate.quota, 1)) *
|
||||
(storageEstimate.usage as number / Math.max(storageEstimate.quota as number, 1)) *
|
||||
100
|
||||
)}
|
||||
%)
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useRef } from "react";
|
||||
import { ChangeEvent, useRef } from "react";
|
||||
import { Box, Label, Input, Button, Flex, Checkbox } from "theme-ui";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import shortid from "shortid";
|
||||
@@ -9,20 +9,20 @@ import useSetting from "../hooks/useSetting";
|
||||
|
||||
import Modal from "../components/Modal";
|
||||
|
||||
function StartModal({ isOpen, onRequestClose }) {
|
||||
function StartModal({ isOpen, onRequestClose }: { isOpen: boolean, onRequestClose: () => void}) {
|
||||
let history = useHistory();
|
||||
const { password, setPassword } = useAuth();
|
||||
|
||||
function handlePasswordChange(event) {
|
||||
function handlePasswordChange(event: ChangeEvent<HTMLInputElement>) {
|
||||
setPassword(event.target.value);
|
||||
}
|
||||
|
||||
const [usePassword, setUsePassword] = useSetting("game.usePassword");
|
||||
function handleUsePasswordChange(event) {
|
||||
function handleUsePasswordChange(event: ChangeEvent<HTMLInputElement>) {
|
||||
setUsePassword(event.target.checked);
|
||||
}
|
||||
|
||||
function handleSubmit(event) {
|
||||
function handleSubmit(event: ChangeEvent<HTMLInputElement>) {
|
||||
event.preventDefault();
|
||||
if (!usePassword) {
|
||||
setPassword("");
|
||||
@@ -30,7 +30,7 @@ function StartModal({ isOpen, onRequestClose }) {
|
||||
history.push(`/game/${shortid.generate()}`);
|
||||
}
|
||||
|
||||
const inputRef = useRef();
|
||||
const inputRef = useRef<any>();
|
||||
function focusInput() {
|
||||
inputRef.current && inputRef.current.focus();
|
||||
}
|
||||
@@ -1,8 +1,19 @@
|
||||
import React from "react";
|
||||
import { Box, Text, Button, Label, Flex } from "theme-ui";
|
||||
|
||||
import Modal from "../components/Modal";
|
||||
|
||||
type StartStreamProps = {
|
||||
isOpen: boolean,
|
||||
onRequestClose: () => void,
|
||||
isSupported: boolean,
|
||||
unavailableMessage: string,
|
||||
stream: MediaStream,
|
||||
noAudioTrack: boolean,
|
||||
noAudioMessage: string,
|
||||
onStreamStart: any,
|
||||
onStreamEnd: any,
|
||||
}
|
||||
|
||||
function StartStreamModal({
|
||||
isOpen,
|
||||
onRequestClose,
|
||||
@@ -13,7 +24,7 @@ function StartStreamModal({
|
||||
noAudioMessage,
|
||||
onStreamStart,
|
||||
onStreamEnd,
|
||||
}) {
|
||||
}: StartStreamProps) {
|
||||
return (
|
||||
<Modal isOpen={isOpen} onRequestClose={onRequestClose}>
|
||||
<Box>
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useRef } from "react";
|
||||
import { ChangeEvent, useRef } from "react";
|
||||
import { Box, Label, Input, Button, Flex, Text } from "theme-ui";
|
||||
|
||||
import Modal from "../components/Modal";
|
||||
@@ -7,14 +7,22 @@ import { getHMSDuration, getDurationHMS } from "../helpers/timer";
|
||||
|
||||
import useSetting from "../hooks/useSetting";
|
||||
|
||||
type StartTimerProps = {
|
||||
isOpen: boolean,
|
||||
onRequestClose: () => void,
|
||||
onTimerStart: any,
|
||||
onTimerStop: any,
|
||||
timer: any,
|
||||
}
|
||||
|
||||
function StartTimerModal({
|
||||
isOpen,
|
||||
onRequestClose,
|
||||
onTimerStart,
|
||||
onTimerStop,
|
||||
timer,
|
||||
}) {
|
||||
const inputRef = useRef();
|
||||
}: StartTimerProps) {
|
||||
const inputRef = useRef<any>();
|
||||
function focusInput() {
|
||||
inputRef.current && inputRef.current.focus();
|
||||
}
|
||||
@@ -23,7 +31,7 @@ function StartTimerModal({
|
||||
const [minute, setMinute] = useSetting("timer.minute");
|
||||
const [second, setSecond] = useSetting("timer.second");
|
||||
|
||||
function handleSubmit(event) {
|
||||
function handleSubmit(event: ChangeEvent<HTMLInputElement>) {
|
||||
event.preventDefault();
|
||||
if (timer) {
|
||||
onTimerStop();
|
||||
@@ -44,7 +52,7 @@ function StartTimerModal({
|
||||
paddingLeft: 0,
|
||||
};
|
||||
|
||||
function parseValue(value, max) {
|
||||
function parseValue(value: string, max: number) {
|
||||
const num = parseInt(value);
|
||||
if (isNaN(num)) {
|
||||
return 0;
|
||||
Reference in New Issue
Block a user