Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor state mgmt #1326

Draft
wants to merge 14 commits into
base: master
Choose a base branch
from
15 changes: 0 additions & 15 deletions frontend/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,25 +46,10 @@ let App = {
packs: 3,
cubePoolSize: 90,

addBots: true,
shufflePlayers: true,
useTimer: true,
timerLength: "Moderate", // Fast Moderate or Slow

beep: true,
notify: false,
notificationGranted: false,
chat: false,
cols: false,
hidepicks: false,
deckSize: 40,
filename: "filename",
filetype: "txt",
side: false,
sort: "rarity",
log: {},
cardSize: "normal",
cardLang: "en",
game: {},
mtgJsonVersion: {
version: "0.0.0",
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/components/Checkbox.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PropTypes from "prop-types";

import App from "../app";

const Checkbox = ({link, text, side, onChange, ...rest}) => (
const Checkbox = ({link, text, side, onChange, value, ...rest}) => (
HerveH44 marked this conversation as resolved.
Show resolved Hide resolved
<div>
{side === "right" ? text : ""}
<input
Expand All @@ -12,7 +12,7 @@ const Checkbox = ({link, text, side, onChange, ...rest}) => (
onChange={onChange || function (e) {
App.save(link, e.currentTarget.checked);
}}
checked={App.state[link]}/>
checked={value || App.state[link]}/>
{side === "left" ? text : ""}
</div>
);
Expand All @@ -21,6 +21,7 @@ Checkbox.propTypes = {
link: PropTypes.string,
text: PropTypes.string,
side: PropTypes.string,
value: PropTypes.any,
onChange: PropTypes.func
};

Expand Down
7 changes: 4 additions & 3 deletions frontend/src/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {vanillaToast} from "vanilla-toast";
import DOMPurify from "dompurify";
import {range, times, constant, countBy} from "lodash";
import {ZONE_JUNK, ZONE_MAIN, ZONE_PACK, ZONE_SIDEBOARD} from "./zones";
import store from "./state/store";

/**
* @desc this is the list of all the events that can be triggered by the App
Expand Down Expand Up @@ -61,9 +62,9 @@ const events = {
hash();
},
start() {
const {addBots, useTimer, timerLength, shufflePlayers} = App.state;
const options = {addBots, useTimer, timerLength, shufflePlayers};
App.send("start", options);
App.send("start", {
...store.getState().startControls
});
},
pickNumber(pick) {
App.save("pickNumber", pick);
Expand Down
260 changes: 150 additions & 110 deletions frontend/src/game/GameSettings.jsx
Original file line number Diff line number Diff line change
@@ -1,132 +1,172 @@
import { capitalize } from "lodash";
import React from "react";
import { useDispatch, useSelector } from "react-redux";

import App from "../app";
import Checkbox from "../components/Checkbox";
import './GameSettings.scss';
import { imgLanguageDisplay, selectBeep, selectCardLang, setNotificationResult, changeSort, toggleCols, selectCardSize, selectChat, selectHidepicks, notificationBlocked, selectNotify, selectSort, toggleChat, toggleNotify, toggleBeep, selectSide, toggleSide, toggleHidepicks, selectCols, sortChoices, sizeDisplay, changeCardSize, changeCardLang } from "../state/game-settings";
import "./GameSettings.scss";

const GameSettings = () => (
<div className='Game-Settings'>
<fieldset className='fieldset'>
<legend className='legend game-legend'>Settings</legend>
<span>
<Checkbox side="left" text="Show chat" link="chat" />
{!App.state.isSealed &&
<Checkbox side="left" text="Enable notifications on new packs" link="beep" />
const GameSettings = () => {
const dispatch = useDispatch();
const beep = useSelector(selectBeep);
const notify = useSelector(selectNotify);
const isNotificationBlocked = useSelector(notificationBlocked);
const chat = useSelector(selectChat);
const side = useSelector(selectSide);
const hidePicks = useSelector(selectHidepicks);
const cols = useSelector(selectCols);

//TODO: that could go inside the reducer? But it has an async behavior ...
const onNotificationChange = () => {
if (!notify) {
dispatch(toggleNotify());
} else if ("Notification" in window) {
Notification.requestPermission().then((result) => {
dispatch(setNotificationResult(result));
if (result === "granted") {
dispatch(toggleNotify());
}
{!App.state.isSealed &&
});
} else {
dispatch(setNotificationResult("notsupported"));
if (notify) {
dispatch(toggleNotify());
}
}
};

return (
<div className='Game-Settings'>
<fieldset className='fieldset'>
<legend className='legend game-legend'>Settings</legend>
<span>
<Checkbox
side="left"
text="Show chat"
value={chat}
onChange={() => dispatch(toggleChat())} />
{!App.state.isSealed &&
<Checkbox
side="left"
text="Enable notifications on new packs"
value={beep}
onChange={() => dispatch(toggleBeep())} />
}
{!App.state.isSealed &&
<div style={{paddingLeft: "10px"}} >
<Checkbox side="left"
text={App.state.notificationBlocked ? "Web notifications blocked in browser" : "Use desktop notifications over beep"}
link="notify"
disabled={!App.state.beep || App.state.notificationBlocked}
onChange={App._emit("notification")} />
text={isNotificationBlocked ? "Web notifications blocked in browser" : "Use desktop notifications over beep"}
value={notify}
disabled={!beep || isNotificationBlocked}
onChange={onNotificationChange} />
</div>
}
{!App.state.isSealed &&
<Checkbox side="left" text="Add picks to sideboard" link="side" />}
{!App.state.isSealed &&
<Checkbox side="left" text="Hide your picks" link="hidepicks" />
}
<Checkbox side="left" text="Use column view" link="cols" />
<SortCards />
<CardsImageQuality />
{App.state.cardSize != "text" && <CardsImageLanguage />}
</span>
</fieldset>
</div>
);
}
{!App.state.isSealed &&
<Checkbox
side="left"
text="Add picks to sideboard"
value={side}
onChange={() => dispatch(toggleSide())} />}
{!App.state.isSealed &&
<Checkbox
side="left"
text="Hide your picks"
value={hidePicks}
onChange={() => dispatch(toggleHidepicks())} />}
<Checkbox
side="left"
text="Use column view"
value={cols}
onChange={() => dispatch(toggleCols())} />
<SortCards />
<CardsImageQuality />
{App.state.cardSize != "text" && <CardsImageLanguage />}
</span>
</fieldset>
</div>
);
};

const SortCards = () => (
<div className="sort-cards">
Sort cards by:
<div className='connected-container' >
{["CMC", "Color", "Type", "Rarity"].map((sort, index) => {
const isActive = sort.toLowerCase() === App.state.sort
const SortCards = () => {
const dispatch = useDispatch();
const sortValue = useSelector(selectSort);
return (
<div className="sort-cards">
Sort cards by:
<div className='connected-container' >
{sortChoices.map((sort, index) => {
const isActive = sort === sortValue;

return (
<label key={index}
className={isActive
? "active connected-component"
: "connected-component"
}
>
<input checked= {isActive}
className='radio-input'
name= 'sort-order'
onChange= {e => App.save("sort", e.currentTarget.value)}
type='radio'
value={sort.toLowerCase()}
/>
<div>{sort}</div>
</label>
)
})}
return (
<label
key={index}
className={isActive ? "active connected-component" : "connected-component"}>
<input checked= {isActive}
className='radio-input'
name= 'sort-order'
onChange= {e => dispatch(changeSort(e.currentTarget.value))}
type='radio'
value={sort}
/>
<div>{capitalize(sort)}</div>
</label>
);
})}
</div>
</div>
</div>
);

const sizeDisplay = {
"text": "Text-Only",
"small": "Low",
"normal": "Medium",
"large": "High",
};
);};

const CardsImageQuality = () => (
<div className="card-quality">
const CardsImageQuality = () => {
const dispatch = useDispatch();
const cardSize = useSelector(selectCardSize);
const cardLang = useSelector(selectCardLang);
return (
<div className="card-quality">
Card image quality:
<div className='connected-container'>
{Object.keys(sizeDisplay).map((size, index) => {
const isActive = size.toLowerCase() === App.state.cardSize
<div className='connected-container'>
{Object.keys(sizeDisplay).map((size, index) => {
const isActive = size === cardSize;

return (
<label key={index}
className={isActive
? "active connected-component"
: "connected-component"
}
>
<input checked={isActive}
className='radio-input'
name='card-size'
onChange={e => App.save("cardSize", e.currentTarget.value)}
type='radio'
value={size.toLowerCase()} />
<div>{sizeDisplay[size]}</div>
</label>
)
})}
return (
<label key={index}
className={isActive
? "active connected-component"
: "connected-component"
}
>
<input checked={isActive}
className='radio-input'
name='card-size'
onChange={e => dispatch(changeCardSize(e.currentTarget.value))}
type='radio'
value={size} />
<div>{sizeDisplay[size]}</div>
</label>
);
})}
</div>
</div>
</div>
);

const imgLanguageDisplay = {
"en": "English",
"fr": "French (Français)",
"es": "Spanish (Español)",
"de": "German (Deutsch)",
"it": "Italian (Italiano)",
"pt": "Portuguese (Português)",
"ja": "Japanese (日本語)",
"ko": "Korean (한국어)",
"ru": "Russian (Русский)",
"zhs": "Simplified Chinese (简体中文)",
"zht": "Traditional Chinese (繁體中文)"
);
};

const CardsImageLanguage = () => (
<div className="cards-language">
const CardsImageLanguage = () => {
const dispatch = useDispatch();
const cardLang = useSelector(selectCardLang);
return (
<div className="cards-language">
Card image language:
<div className='connected-container'>
<select
value={App.state.cardLang}
onChange={e => App.save("cardLang", e.currentTarget.value)}>
{Object.entries(imgLanguageDisplay).map(([value, label]) =>
<option key={value} value={value}>{label}</option>
)}
</select>
<div className='connected-container'>
<select
value={cardLang}
onChange={e => dispatch(changeCardLang(e.currentTarget.value))}>
{Object.entries(imgLanguageDisplay).map(([value, label]) =>
<option key={value} value={value}>{label}</option>
)}
</select>
</div>
</div>
</div>
);
);
};

export default GameSettings;