Skip to content
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}) => (
Comment thread
HerveH44 marked this conversation as 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;
Loading