Fix regressions
This commit is contained in:
parent
388437ce7e
commit
1f60acc517
10 changed files with 25 additions and 663 deletions
|
@ -1,614 +0,0 @@
|
|||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { nanoid } from "nanoid";
|
||||
import { toast } from "react-toastify";
|
||||
import { useSetRecoilState, useRecoilCallback } from "recoil";
|
||||
|
||||
import { useItemActions } from "../board/Items";
|
||||
import { SelectedItemsAtom } from "../board";
|
||||
import { useUsers } from "../users";
|
||||
import { ItemMapAtom } from "../board";
|
||||
|
||||
import { shuffle as shuffleArray, randInt } from "../utils";
|
||||
|
||||
import deleteIcon from "../images/delete.svg";
|
||||
import stackToCenterIcon from "../images/stackToCenter.svg";
|
||||
import stackToTopLeftIcon from "../images/stackToTopLeft.svg";
|
||||
import alignAsLineIcon from "../images/alignAsLine.svg";
|
||||
import alignAsSquareIcon from "../images/alignAsSquare.svg";
|
||||
import duplicateIcon from "../images/duplicate.svg";
|
||||
import seeIcon from "../images/see.svg";
|
||||
import flipIcon from "../images/flip.svg";
|
||||
import lockIcon from "../images/lock.svg";
|
||||
import rotateIcon from "../images/rotate.svg";
|
||||
import shuffleIcon from "../images/shuffle.svg";
|
||||
import tapIcon from "../images/tap.svg";
|
||||
|
||||
import useLocalStorage from "../hooks/useLocalStorage";
|
||||
|
||||
export const useGameItemActionMap = () => {
|
||||
const {
|
||||
batchUpdateItems,
|
||||
removeItems,
|
||||
insertItemBefore,
|
||||
reverseItemsOrder,
|
||||
swapItems,
|
||||
} = useItemActions();
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [isFirstLock, setIsFirstLock] = useLocalStorage("isFirstLock", true);
|
||||
|
||||
const { currentUser } = useUsers();
|
||||
|
||||
const setSelectedItems = useSetRecoilState(SelectedItemsAtom);
|
||||
const isMountedRef = React.useRef(false);
|
||||
|
||||
const getItemListOrSelected = useRecoilCallback(
|
||||
({ snapshot }) => async (itemIds) => {
|
||||
const itemMap = await snapshot.getPromise(ItemMapAtom);
|
||||
if (itemIds) {
|
||||
return [itemIds, itemIds.map((id) => itemMap[id])];
|
||||
} else {
|
||||
const selectedItems = await snapshot.getPromise(SelectedItemsAtom);
|
||||
return [selectedItems, selectedItems.map((id) => itemMap[id])];
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
// Mounted guard
|
||||
isMountedRef.current = true;
|
||||
return () => {
|
||||
isMountedRef.current = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Stack selection to Center
|
||||
const stackToCenter = React.useCallback(
|
||||
async (
|
||||
itemIds,
|
||||
{
|
||||
stackThicknessMin = 0.5,
|
||||
stackThicknessMax = 1,
|
||||
limitCardsNumber = 32,
|
||||
} = {}
|
||||
) => {
|
||||
const [ids, items] = await getItemListOrSelected(itemIds);
|
||||
|
||||
// Rule to manage thickness of the stack.
|
||||
let stackThickness = stackThicknessMax;
|
||||
if (items.length >= limitCardsNumber) {
|
||||
stackThickness = stackThicknessMin;
|
||||
}
|
||||
|
||||
// To avoid displacement effects.
|
||||
let isSameGap = true;
|
||||
for (let i = 1; i < items.length; i++) {
|
||||
if (Math.abs(items[i].x - items[i - 1].x) != stackThickness) {
|
||||
isSameGap = false;
|
||||
break;
|
||||
}
|
||||
if (Math.abs(items[i].y - items[i - 1].y) != stackThickness) {
|
||||
isSameGap = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isSameGap == true) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute middle position
|
||||
const minMax = { min: {}, max: {} };
|
||||
minMax.min.x = Math.min(...items.map(({ x }) => x));
|
||||
minMax.min.y = Math.min(...items.map(({ y }) => y));
|
||||
minMax.max.x = Math.max(
|
||||
...items.map(({ x, id }) => x + document.getElementById(id).clientWidth)
|
||||
);
|
||||
minMax.max.y = Math.max(
|
||||
...items.map(
|
||||
({ y, id }) => y + document.getElementById(id).clientHeight
|
||||
)
|
||||
);
|
||||
const { clientWidth, clientHeight } = document.getElementById(
|
||||
items[0].id
|
||||
);
|
||||
let newX =
|
||||
minMax.min.x + (minMax.max.x - minMax.min.x) / 2 - clientWidth / 2;
|
||||
let newY =
|
||||
minMax.min.y + (minMax.max.y - minMax.min.y) / 2 - clientHeight / 2;
|
||||
|
||||
batchUpdateItems(ids, (item) => {
|
||||
const newItem = {
|
||||
...item,
|
||||
x: newX,
|
||||
y: newY,
|
||||
};
|
||||
newX += stackThickness;
|
||||
newY -= stackThickness;
|
||||
return newItem;
|
||||
});
|
||||
},
|
||||
[batchUpdateItems, getItemListOrSelected]
|
||||
);
|
||||
|
||||
// Stack selection to Top Left
|
||||
const stackToTopLeft = React.useCallback(
|
||||
async (
|
||||
itemIds,
|
||||
{
|
||||
stackThicknessMin = 0.5,
|
||||
stackThicknessMax = 1,
|
||||
limitCardsNumber = 32,
|
||||
} = {}
|
||||
) => {
|
||||
const [ids, items] = await getItemListOrSelected(itemIds);
|
||||
|
||||
let { x: newX, y: newY } = items[0];
|
||||
|
||||
// Rule to manage thickness of the stack.
|
||||
let stackThickness = stackThicknessMax;
|
||||
if (items.length >= limitCardsNumber) {
|
||||
stackThickness = stackThicknessMin;
|
||||
}
|
||||
|
||||
batchUpdateItems(ids, (item) => {
|
||||
const newItem = {
|
||||
...item,
|
||||
x: newX,
|
||||
y: newY,
|
||||
};
|
||||
newX += stackThickness;
|
||||
newY -= stackThickness;
|
||||
return newItem;
|
||||
});
|
||||
},
|
||||
[batchUpdateItems, getItemListOrSelected]
|
||||
);
|
||||
|
||||
// Align selection to a line
|
||||
const alignAsLine = React.useCallback(
|
||||
async (itemIds, { gapBetweenItems = 5 } = {}) => {
|
||||
// Negative value is possible for 'gapBetweenItems'.
|
||||
const [ids, items] = await getItemListOrSelected(itemIds);
|
||||
|
||||
let { x: newX, y: newY } = items[0];
|
||||
|
||||
batchUpdateItems(ids, (item) => {
|
||||
const { clientWidth } = document.getElementById(item.id);
|
||||
const newItem = {
|
||||
...item,
|
||||
x: newX,
|
||||
y: newY,
|
||||
};
|
||||
newX += clientWidth + gapBetweenItems;
|
||||
return newItem;
|
||||
});
|
||||
},
|
||||
[getItemListOrSelected, batchUpdateItems]
|
||||
);
|
||||
|
||||
// Align selection to an array
|
||||
const alignAsSquare = React.useCallback(
|
||||
async (itemIds, { gapBetweenItems = 5 } = {}) => {
|
||||
// Negative value is possible for 'gapBetweenItems'.
|
||||
const [ids, items] = await getItemListOrSelected(itemIds);
|
||||
|
||||
// Count number of elements
|
||||
const numberOfElements = items.length;
|
||||
const numberOfColumns = Math.ceil(Math.sqrt(numberOfElements));
|
||||
|
||||
let { x: newX, y: newY } = items[0];
|
||||
|
||||
let currentColumn = 1;
|
||||
|
||||
batchUpdateItems(ids, (item) => {
|
||||
const { clientWidth, clientHeight } = document.getElementById(item.id);
|
||||
const newItem = {
|
||||
...item,
|
||||
x: newX,
|
||||
y: newY,
|
||||
};
|
||||
newX += clientWidth + gapBetweenItems;
|
||||
currentColumn += 1;
|
||||
if (currentColumn > numberOfColumns) {
|
||||
currentColumn = 1;
|
||||
newX = items[0].x;
|
||||
newY += clientHeight + gapBetweenItems;
|
||||
}
|
||||
return newItem;
|
||||
});
|
||||
},
|
||||
[getItemListOrSelected, batchUpdateItems]
|
||||
);
|
||||
|
||||
const shuffleItems = React.useCallback(
|
||||
async (itemIds) => {
|
||||
const [ids] = await getItemListOrSelected(itemIds);
|
||||
|
||||
ids.forEach((itemId) => {
|
||||
const elem = document.getElementById(itemId);
|
||||
elem.firstChild.className = "hvr-wobble-horizontal";
|
||||
});
|
||||
const shuffledItems = shuffleArray([...ids]);
|
||||
swapItems(ids, shuffledItems);
|
||||
},
|
||||
[getItemListOrSelected, swapItems]
|
||||
);
|
||||
|
||||
const randomlyRotateSelectedItems = React.useCallback(
|
||||
async (itemIds, { angle, maxRotateCount }) => {
|
||||
const [ids] = await getItemListOrSelected(itemIds);
|
||||
|
||||
batchUpdateItems(ids, (item) => {
|
||||
const rotation =
|
||||
((item.rotation || 0) + angle * randInt(0, maxRotateCount)) % 360;
|
||||
return { ...item, rotation };
|
||||
});
|
||||
},
|
||||
[getItemListOrSelected, batchUpdateItems]
|
||||
);
|
||||
|
||||
// Tap/Untap elements
|
||||
const toggleTap = React.useCallback(
|
||||
async (itemIds) => {
|
||||
const [ids, items] = await getItemListOrSelected(itemIds);
|
||||
|
||||
const tappedCount = items.filter(({ rotation }) => rotation === 90)
|
||||
.length;
|
||||
|
||||
let untap = false;
|
||||
if (tappedCount > ids.length / 2) {
|
||||
untap = true;
|
||||
}
|
||||
|
||||
batchUpdateItems(ids, (item) => ({
|
||||
...item,
|
||||
rotation: untap ? 0 : 90,
|
||||
}));
|
||||
},
|
||||
[getItemListOrSelected, batchUpdateItems]
|
||||
);
|
||||
|
||||
// Lock / unlock elements
|
||||
const toggleLock = React.useCallback(
|
||||
async (itemIds) => {
|
||||
const [ids] = await getItemListOrSelected(itemIds);
|
||||
|
||||
batchUpdateItems(ids, (item) => ({
|
||||
...item,
|
||||
locked: !item.locked,
|
||||
}));
|
||||
|
||||
// Help user on first lock
|
||||
if (isFirstLock) {
|
||||
toast.info(
|
||||
t("You've locked your first element. Long click to select it again."),
|
||||
{ autoClose: false }
|
||||
);
|
||||
setIsFirstLock(false);
|
||||
}
|
||||
},
|
||||
[getItemListOrSelected, batchUpdateItems, isFirstLock, t, setIsFirstLock]
|
||||
);
|
||||
|
||||
// Flip or reveal items
|
||||
const setFlip = React.useCallback(
|
||||
async (itemIds, { flip = true, reverseOrder = true } = {}) => {
|
||||
batchUpdateItems(itemIds, (item) => ({
|
||||
...item,
|
||||
flipped: flip,
|
||||
unflippedFor:
|
||||
!Array.isArray(item.unflippedFor) || item.unflippedFor.length > 0
|
||||
? null
|
||||
: item.unflippedFor,
|
||||
}));
|
||||
if (reverseOrder) {
|
||||
reverseItemsOrder(itemIds);
|
||||
setSelectedItems((prev) => {
|
||||
const reversed = [...prev];
|
||||
reversed.reverse();
|
||||
return reversed;
|
||||
});
|
||||
}
|
||||
},
|
||||
[batchUpdateItems, reverseItemsOrder, setSelectedItems]
|
||||
);
|
||||
|
||||
// Toggle flip state
|
||||
const toggleFlip = React.useCallback(
|
||||
async (itemIds, { reverseOrder = true } = {}) => {
|
||||
const [ids, items] = await getItemListOrSelected(itemIds);
|
||||
|
||||
const flippedCount = items.filter(({ flipped }) => flipped).length;
|
||||
|
||||
setFlip(ids, {
|
||||
flip: flippedCount < ids.length / 2,
|
||||
reverseOrder,
|
||||
});
|
||||
},
|
||||
[getItemListOrSelected, setFlip]
|
||||
);
|
||||
|
||||
// Rotate element
|
||||
const rotate = React.useCallback(
|
||||
async (itemIds, { angle }) => {
|
||||
const [ids] = await getItemListOrSelected(itemIds);
|
||||
|
||||
batchUpdateItems(ids, (item) => ({
|
||||
...item,
|
||||
rotation: (item.rotation || 0) + angle,
|
||||
}));
|
||||
},
|
||||
[getItemListOrSelected, batchUpdateItems]
|
||||
);
|
||||
|
||||
// Reveal for player only
|
||||
const setFlipSelf = React.useCallback(
|
||||
async (itemIds, { flipSelf = true } = {}) => {
|
||||
batchUpdateItems(itemIds, (item) => {
|
||||
let { unflippedFor = [] } = item;
|
||||
|
||||
if (!Array.isArray(item.unflippedFor)) {
|
||||
unflippedFor = [];
|
||||
}
|
||||
|
||||
if (flipSelf && !unflippedFor.includes(currentUser.uid)) {
|
||||
unflippedFor = [...unflippedFor, currentUser.uid];
|
||||
}
|
||||
if (!flipSelf && unflippedFor.includes(currentUser.uid)) {
|
||||
unflippedFor = unflippedFor.filter((id) => id !== currentUser.uid);
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
flipped: true,
|
||||
unflippedFor,
|
||||
};
|
||||
});
|
||||
},
|
||||
[batchUpdateItems, currentUser.uid]
|
||||
);
|
||||
|
||||
// Reveal for player only
|
||||
const toggleFlipSelf = React.useCallback(
|
||||
async (itemIds) => {
|
||||
const [ids, items] = await getItemListOrSelected(itemIds);
|
||||
|
||||
const flippedSelfCount = items.filter(
|
||||
({ unflippedFor }) =>
|
||||
Array.isArray(unflippedFor) && unflippedFor.includes(currentUser.uid)
|
||||
).length;
|
||||
|
||||
let flipSelf = true;
|
||||
if (flippedSelfCount > ids.length / 2) {
|
||||
flipSelf = false;
|
||||
}
|
||||
|
||||
setFlipSelf(ids, { flipSelf });
|
||||
},
|
||||
[getItemListOrSelected, setFlipSelf, currentUser.uid]
|
||||
);
|
||||
|
||||
const remove = React.useCallback(
|
||||
async (itemIds) => {
|
||||
const [ids] = await getItemListOrSelected(itemIds);
|
||||
removeItems(ids);
|
||||
},
|
||||
[getItemListOrSelected, removeItems]
|
||||
);
|
||||
|
||||
const cloneItem = React.useCallback(
|
||||
async (itemIds) => {
|
||||
const [, items] = await getItemListOrSelected(itemIds);
|
||||
items.forEach((itemToClone) => {
|
||||
const newItem = JSON.parse(JSON.stringify(itemToClone));
|
||||
newItem.id = nanoid();
|
||||
delete newItem.move;
|
||||
insertItemBefore(newItem, itemToClone.id);
|
||||
});
|
||||
},
|
||||
[getItemListOrSelected, insertItemBefore]
|
||||
);
|
||||
|
||||
const actionMap = React.useMemo(
|
||||
() => ({
|
||||
flip: {
|
||||
action: toggleFlip,
|
||||
label: t("Reveal") + "/" + t("Hide"),
|
||||
shortcut: "f",
|
||||
icon: flipIcon,
|
||||
},
|
||||
reveal: {
|
||||
action: (itemIds) => setFlip(itemIds, { flip: false }),
|
||||
label: t("Reveal"),
|
||||
icon: flipIcon,
|
||||
},
|
||||
hide: {
|
||||
action: (itemIds) => setFlip(itemIds, { flip: true }),
|
||||
label: t("Hide"),
|
||||
icon: flipIcon,
|
||||
},
|
||||
flipSelf: {
|
||||
action: toggleFlipSelf,
|
||||
label: t("Reveal for me"),
|
||||
shortcut: "o",
|
||||
icon: seeIcon,
|
||||
},
|
||||
revealSelf: {
|
||||
action: (itemIds) => setFlipSelf(itemIds, { flipSelf: true }),
|
||||
label: t("Reveal for me"),
|
||||
icon: seeIcon,
|
||||
},
|
||||
hideSelf: {
|
||||
action: (itemIds) => setFlipSelf(itemIds, { flipSelf: false }),
|
||||
label: t("Hide for me"),
|
||||
icon: seeIcon,
|
||||
},
|
||||
tap: {
|
||||
action: toggleTap,
|
||||
label: t("Tap") + "/" + t("Untap"),
|
||||
shortcut: "t",
|
||||
icon: tapIcon,
|
||||
},
|
||||
stackToCenter: {
|
||||
action: stackToCenter,
|
||||
label: t("Stack To Center"),
|
||||
shortcut: "",
|
||||
multiple: true,
|
||||
icon: stackToCenterIcon,
|
||||
},
|
||||
stack: {
|
||||
action: stackToTopLeft,
|
||||
label: t("Stack To Top Left"),
|
||||
multiple: true,
|
||||
icon: stackToTopLeftIcon,
|
||||
},
|
||||
alignAsLine: {
|
||||
action: alignAsLine,
|
||||
label: t("Align as line"),
|
||||
multiple: true,
|
||||
icon: alignAsLineIcon,
|
||||
},
|
||||
alignAsSquare: {
|
||||
action: alignAsSquare,
|
||||
label: t("Align as square"),
|
||||
multiple: true,
|
||||
icon: alignAsSquareIcon,
|
||||
},
|
||||
shuffle: {
|
||||
action: shuffleItems,
|
||||
label: t("Shuffle"),
|
||||
multiple: true,
|
||||
icon: shuffleIcon,
|
||||
},
|
||||
randomlyRotate30: {
|
||||
action: (itemIds) =>
|
||||
randomlyRotateSelectedItems(itemIds, {
|
||||
angle: 30,
|
||||
maxRotateCount: 11,
|
||||
}),
|
||||
label: t("Rotate randomly 30"),
|
||||
multiple: false,
|
||||
icon: rotateIcon,
|
||||
},
|
||||
randomlyRotate45: {
|
||||
action: (itemIds) =>
|
||||
randomlyRotateSelectedItems(itemIds, {
|
||||
angle: 45,
|
||||
maxRotateCount: 7,
|
||||
}),
|
||||
label: t("Rotate randomly 45"),
|
||||
shortcut: "",
|
||||
multiple: false,
|
||||
icon: rotateIcon,
|
||||
},
|
||||
randomlyRotate60: {
|
||||
action: (itemIds) =>
|
||||
randomlyRotateSelectedItems(itemIds, {
|
||||
angle: 60,
|
||||
maxRotateCount: 5,
|
||||
}),
|
||||
label: t("Rotate randomly 60"),
|
||||
shortcut: "",
|
||||
multiple: false,
|
||||
icon: rotateIcon,
|
||||
},
|
||||
randomlyRotate90: {
|
||||
action: (itemIds) =>
|
||||
randomlyRotateSelectedItems(itemIds, {
|
||||
angle: 90,
|
||||
maxRotateCount: 3,
|
||||
}),
|
||||
label: t("Rotate randomly 90"),
|
||||
shortcut: "",
|
||||
multiple: false,
|
||||
icon: rotateIcon,
|
||||
},
|
||||
randomlyRotate180: {
|
||||
action: (itemIds) =>
|
||||
randomlyRotateSelectedItems(itemIds, {
|
||||
angle: 180,
|
||||
maxRotateCount: 1,
|
||||
}),
|
||||
label: t("Rotate randomly 180"),
|
||||
shortcut: "",
|
||||
multiple: false,
|
||||
icon: rotateIcon,
|
||||
},
|
||||
rotate30: {
|
||||
action: (itemIds) => rotate(itemIds, { angle: 30 }),
|
||||
label: t("Rotate 30"),
|
||||
shortcut: "r",
|
||||
icon: rotateIcon,
|
||||
},
|
||||
rotate45: {
|
||||
action: (itemIds) => rotate(itemIds, { angle: 45 }),
|
||||
label: t("Rotate 45"),
|
||||
shortcut: "r",
|
||||
icon: rotateIcon,
|
||||
},
|
||||
rotate60: {
|
||||
action: (itemIds) => rotate(itemIds, { angle: 60 }),
|
||||
label: t("Rotate 60"),
|
||||
shortcut: "r",
|
||||
icon: rotateIcon,
|
||||
},
|
||||
rotate90: {
|
||||
action: (itemIds) => rotate(itemIds, { angle: 90 }),
|
||||
label: t("Rotate 90"),
|
||||
shortcut: "r",
|
||||
icon: rotateIcon,
|
||||
},
|
||||
rotate180: {
|
||||
action: (itemIds) => rotate(itemIds, { angle: 180 }),
|
||||
label: t("Rotate 180"),
|
||||
shortcut: "r",
|
||||
icon: rotateIcon,
|
||||
},
|
||||
clone: {
|
||||
action: cloneItem,
|
||||
label: t("Clone"),
|
||||
shortcut: "c",
|
||||
disableDblclick: true,
|
||||
edit: true,
|
||||
icon: duplicateIcon,
|
||||
},
|
||||
lock: {
|
||||
action: toggleLock,
|
||||
label: t("Unlock") + "/" + t("Lock"),
|
||||
disableDblclick: true,
|
||||
icon: lockIcon,
|
||||
},
|
||||
remove: {
|
||||
action: remove,
|
||||
label: t("Remove all"),
|
||||
shortcut: "Delete",
|
||||
edit: true,
|
||||
disableDblclick: true,
|
||||
icon: deleteIcon,
|
||||
},
|
||||
}),
|
||||
[
|
||||
toggleFlip,
|
||||
t,
|
||||
toggleFlipSelf,
|
||||
toggleTap,
|
||||
stackToCenter,
|
||||
stackToTopLeft,
|
||||
alignAsLine,
|
||||
alignAsSquare,
|
||||
shuffleItems,
|
||||
cloneItem,
|
||||
toggleLock,
|
||||
remove,
|
||||
setFlip,
|
||||
setFlipSelf,
|
||||
randomlyRotateSelectedItems,
|
||||
rotate,
|
||||
]
|
||||
);
|
||||
|
||||
return { actionMap, setFlip, setFlipSelf, stack: stackToTopLeft };
|
||||
};
|
||||
export default useGameItemActionMap;
|
|
@ -26,7 +26,7 @@ export const useGameItemActions = () => {
|
|||
const {
|
||||
batchUpdateItems,
|
||||
removeItems,
|
||||
insertItemBefore,
|
||||
pushItem,
|
||||
reverseItemsOrder,
|
||||
swapItems,
|
||||
getItems,
|
||||
|
@ -396,10 +396,10 @@ export const useGameItemActions = () => {
|
|||
const newItem = JSON.parse(JSON.stringify(itemToClone));
|
||||
newItem.id = nanoid();
|
||||
delete newItem.move;
|
||||
insertItemBefore(newItem, itemToClone.id);
|
||||
pushItem(newItem, itemToClone.id);
|
||||
});
|
||||
},
|
||||
[getItemListOrSelected, insertItemBefore]
|
||||
[getItemListOrSelected, pushItem]
|
||||
);
|
||||
|
||||
const actionMap = React.useMemo(
|
||||
|
|
|
@ -74,8 +74,8 @@ export const SessionProvider = ({ sessionId, fromGameId, children }) => {
|
|||
async (newData, sync = false) => {
|
||||
const { availableItems, items, board, messages = [] } = newData;
|
||||
setAvailableItems(availableItems);
|
||||
// The filter prevent the empty item bug on reload
|
||||
setItemList(items.filter((item) => item));
|
||||
// The filter prevents the empty item bug or missing type on reload
|
||||
setItemList(items.filter((item) => item && item.type));
|
||||
setBoardConfig(board, false);
|
||||
setMessages(messages);
|
||||
|
||||
|
|
|
@ -5,9 +5,9 @@ import styled from "styled-components";
|
|||
|
||||
const Color = styled.div`
|
||||
background-color: ${({ color }) => color};
|
||||
border: 1px solid #00000022;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid #ffffff66;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin: 5px;
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
|
|
@ -2,29 +2,13 @@ import React from "react";
|
|||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import useSession from "../../hooks/useSession";
|
||||
import { useItems, useBoardConfig, useMessage } from "react-sync-board";
|
||||
|
||||
import DownloadLink from "./DownloadLink";
|
||||
import Modal from "../../ui/Modal";
|
||||
|
||||
const ExportModal = ({ show, setShow }) => {
|
||||
const { t } = useTranslation();
|
||||
const { gameId, availableItems } = useSession();
|
||||
const items = useItems();
|
||||
const [boardConfig] = useBoardConfig();
|
||||
const { messages } = useMessage();
|
||||
|
||||
const getSession = React.useCallback(() => {
|
||||
const currentSession = {
|
||||
items: items,
|
||||
board: boardConfig,
|
||||
availableItems: availableItems,
|
||||
messages: messages.slice(-50),
|
||||
timestamp: Date.now(),
|
||||
gameId: gameId,
|
||||
};
|
||||
return currentSession;
|
||||
}, [availableItems, boardConfig, gameId, items, messages]);
|
||||
const { getSession } = useSession();
|
||||
|
||||
return (
|
||||
<Modal title={t("Save game")} setShow={setShow} show={show}>
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import React from "react";
|
||||
import { useTranslation, Trans } from "react-i18next";
|
||||
import { useRecoilValue } from "recoil";
|
||||
import useAsyncEffect from "use-async-effect";
|
||||
import styled from "styled-components";
|
||||
import { useBoardConfig } from "react-sync-board";
|
||||
|
||||
import Modal from "../../ui/Modal";
|
||||
// import { BoardConfigAtom } from "../../board";
|
||||
|
||||
import { getBestTranslationFromConfig } from "../../utils/api";
|
||||
|
||||
|
@ -30,12 +29,11 @@ const InfoModal = ({ show, setShow }) => {
|
|||
|
||||
const [info, setInfo] = React.useState("");
|
||||
|
||||
// const boardConfig = useRecoilValue(BoardConfigAtom);
|
||||
const [boardConfig] = useBoardConfig();
|
||||
|
||||
const translation = React.useMemo(
|
||||
// () => getBestTranslationFromConfig(boardConfig, i18n.languages),
|
||||
() => getBestTranslationFromConfig({}, i18n.languages),
|
||||
[i18n.languages]
|
||||
() => getBestTranslationFromConfig(boardConfig, i18n.languages),
|
||||
[boardConfig, i18n.languages]
|
||||
);
|
||||
|
||||
useAsyncEffect(
|
||||
|
|
|
@ -104,7 +104,6 @@ const SelectedItemsPane = ({ hideMenu = false, ItemFormComponent }) => {
|
|||
e.key === shortcut &&
|
||||
showEdit === !!whileEdit
|
||||
) {
|
||||
// here
|
||||
action();
|
||||
}
|
||||
});
|
||||
|
@ -133,10 +132,8 @@ const SelectedItemsPane = ({ hideMenu = false, ItemFormComponent }) => {
|
|||
|
||||
if (e.ctrlKey && filteredActions.length > 1) {
|
||||
// Use second action
|
||||
// here
|
||||
actionMap[filteredActions[1]].action();
|
||||
} else if (filteredActions.length > 0) {
|
||||
// here
|
||||
actionMap[filteredActions[0]].action();
|
||||
}
|
||||
},
|
||||
|
@ -206,7 +203,6 @@ const SelectedItemsPane = ({ hideMenu = false, ItemFormComponent }) => {
|
|||
<button
|
||||
className="button clear icon-only"
|
||||
key={action}
|
||||
// here
|
||||
onClick={() => handler()}
|
||||
title={label + (shortcut ? ` (${shortcut})` : "")}
|
||||
>
|
||||
|
|
|
@ -41,7 +41,7 @@ const WelcomeModal = ({ show, setShow, welcome = true }) => {
|
|||
inputRef.current.select();
|
||||
document.execCommand("copy");
|
||||
inputRef.current.style.display = "none";
|
||||
toast.info(t("Url copied to clipboard!"), { autoClose: 100000 });
|
||||
toast.info(t("Url copied to clipboard!"), { autoClose: 1000 });
|
||||
};
|
||||
|
||||
const meetUrl = `https://meet.jit.si/airboardgame__${room}`;
|
||||
|
|
|
@ -202,17 +202,17 @@ const GameListView = () => {
|
|||
);
|
||||
|
||||
const filteredGameList = React.useMemo(() => {
|
||||
return gameList
|
||||
? gameList.filter((game) => {
|
||||
return (
|
||||
(filterCriteria.searchTerm === NULL_SEARCH_TERM ||
|
||||
search(filterCriteria.searchTerm, game.defaultName)) &&
|
||||
hasRequestedValues(filterCriteria.nbOfPlayers, game.playerCount) &&
|
||||
hasRequestedValues(filterCriteria.durations, game.duration) &&
|
||||
hasAllowedMaterialLanguage(filterCriteria, game)
|
||||
);
|
||||
})
|
||||
: [];
|
||||
if (gameList) {
|
||||
return gameList.filter(
|
||||
(game) =>
|
||||
(filterCriteria.searchTerm === NULL_SEARCH_TERM ||
|
||||
search(filterCriteria.searchTerm, game.defaultName)) &&
|
||||
hasRequestedValues(filterCriteria.nbOfPlayers, game.playerCount) &&
|
||||
hasRequestedValues(filterCriteria.durations, game.duration) &&
|
||||
hasAllowedMaterialLanguage(filterCriteria, game)
|
||||
);
|
||||
}
|
||||
return [];
|
||||
}, [gameList, filterCriteria]);
|
||||
|
||||
const onChangeNbOfPlayersSlider = (values) => {
|
||||
|
|
|
@ -83,8 +83,6 @@ const WebConferenceContent = ({ users }) => {
|
|||
setShowLocalAudio((prev) => !prev);
|
||||
}, [setShowLocalAudio]);
|
||||
|
||||
// const { localUsers: users } = useUsers();
|
||||
|
||||
const streamMap = React.useMemo(
|
||||
() =>
|
||||
remoteStreams.reduce((acc, stream) => {
|
||||
|
|
Loading…
Reference in a new issue