Skip to content

Commit

Permalink
Add Language Picker modal as well
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew Casal authored and Andrew Casal committed Oct 7, 2024
1 parent 60e4e9e commit 63bf5f2
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 108 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
{
"[ruby]": {
"editor.formatOnSave": false
}
}
23 changes: 7 additions & 16 deletions src/components/ChallengeModal/ChallengeModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ import {
saveTimeControlSettings,
updateSystem,
} from "@/components/TimeControl/TimeControlUpdates";
import { ModalConsumer } from "../Modal/ModalProvider";

export type ChallengeDetails = rest_api.ChallengeDetails;

Expand Down Expand Up @@ -1792,18 +1791,13 @@ export class ChallengeModal extends Modal<Events, ChallengeModalProperties, any>
</div>
)} */}
<div className="buttons">
<ModalConsumer>
{(value) => (
<button
onClick={() => {
this.close();
value.hideModal();
}}
>
{_("Close")}
</button>
)}
</ModalConsumer>
<button
onClick={() => {
this.close();
}}
>
{_("Close")}
</button>
{mode === "demo" && (
<button onClick={this.createDemo} className="primary">
{this.props.game_record_mode
Expand Down Expand Up @@ -1957,9 +1951,6 @@ export function createDemoBoard(
/>,
);
}
export function challengeComputer() {
return challenge(undefined, null, true);
}
export function challengeRematch(
goban: GobanRenderer,
opponent: GobanEnginePlayerEntry,
Expand Down
112 changes: 50 additions & 62 deletions src/components/LanguagePicker/LanguagePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,8 @@

import * as React from "react";
import { _, setCurrentLanguage, current_language, languages } from "@/lib/translate";
import { Modal, openModal } from "@/components/Modal";
import * as preferences from "@/lib/preferences";

interface Events {}

interface LanguagePickerProperties {}

let language_modal: JSX.Element | null = null;

function openLanguageModal() {
language_modal = <LanguagePickerModal />;
openModal(language_modal);
}
import { ModalConsumer, ModalContext, ModalTypes } from "../Modal/ModalProvider";

function language_sorter(a: string, b: string) {
if (a === "auto") {
Expand All @@ -48,64 +37,63 @@ function language_sorter(a: string, b: string) {
}

export const LanguagePicker = () => (
<span className="LanguagePicker fakelink" onClick={openLanguageModal}>
<i className="fa fa-language" />
{languages[current_language]}
</span>
<ModalConsumer>
{(value) => (
<span
className="LanguagePicker fakelink"
onClick={() => value.showModal(ModalTypes.LanguagePicker)}
>
<i className="fa fa-language" />
{languages[current_language]}
</span>
)}
</ModalConsumer>
);

class LanguagePickerModal extends Modal<Events, LanguagePickerProperties, any> {
constructor(props: LanguagePickerProperties) {
super(props);
this.state = {
selected_language: current_language,
};
}
export const LanguagePickerModal = () => {
const { hideModal } = React.useContext(ModalContext);

setLanguage(language_code: string) {
const setLanguage = (language_code: string) => {
preferences.set("language", language_code);
setCurrentLanguage(language_code);
this.close();
window.location.reload();
}
};

render() {
const auto = preferences.get("language") === "auto";
function computeClass(lc: string) {
let ret = "";
if (auto) {
if (lc === "auto") {
ret += "selected";
} else if (lc === current_language) {
ret += "auto";
}
} else {
if (lc === current_language) {
ret += "selected";
}
const auto = preferences.get("language") === "auto";
function computeClass(lc: string) {
let ret = "";
if (auto) {
if (lc === "auto") {
ret += "selected";
} else if (lc === current_language) {
ret += "auto";
}
} else {
if (lc === current_language) {
ret += "selected";
}
return ret;
}
return ret;
}

return (
<div className="Modal LanguagePickerModal">
<div className="body">
{Object.keys(languages)
.sort(language_sorter)
.map((lc, idx) => (
<span
key={idx}
className={computeClass(lc) + " fakelink language-option"}
onClick={() => this.setLanguage(lc)}
>
{languages[lc]}
</span>
))}
</div>
<div className="footer">
<button onClick={this.close}>{_("Cancel")}</button>
</div>
return (
<div className="Modal LanguagePickerModal">
<div className="body">
{Object.keys(languages)
.sort(language_sorter)
.map((lc, idx) => (
<span
key={idx}
className={computeClass(lc) + " fakelink language-option"}
onClick={() => setLanguage(lc)}
>
{languages[lc]}
</span>
))}
</div>
);
}
}
<div className="footer">
<button onClick={hideModal}>{_("Cancel")}</button>
</div>
</div>
);
};
66 changes: 46 additions & 20 deletions src/components/Modal/ModalProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@ import * as React from "react";

import { ChallengeModal, ChallengeModes } from "../ChallengeModal";
import { createPortal } from "react-dom";
import { deepEqual } from "@/lib/misc";
import { LanguagePickerModal } from "../LanguagePicker";

type ModalProviderType = {
showModal: (types: ModalTypes) => void;
showModal: (type: ModalTypes) => void;
hideModal: () => void;
};

export enum ModalTypes {
Challenge = "challenge",
LanguagePicker = "languagePicker",
}

interface Modals {
Expand All @@ -39,40 +40,65 @@ interface Modals {
};
}

type Property<T, K extends keyof T> = T[K];
type ModalTypesProps = {
[key: string]: any;
};

export const ModalContext = React.createContext({} as ModalProviderType);
const { Provider, Consumer } = ModalContext;

export const ModalConsumer = Consumer;

export const ModalProvider = ({ children }: React.PropsWithChildren): JSX.Element => {
const [modal, setModal] = React.useState(false);
const [props, setProps] = React.useState({} as Property<Modals, ModalTypes>);
const [modalType, setModalType] = React.useState(null as ModalTypes | null);
const [modalProps, setModalProps] = React.useState({} as ModalTypesProps);

function showModal() {
setModal(true);
const showModal = (type: ModalTypes) => {
setModalType(type);

const payload = {
mode: "computer" as ChallengeModes,
initialState: null,
playerId: undefined,
switch (type) {
case ModalTypes.Challenge:
setModalProps({
mode: "computer" as ChallengeModes,
initialState: null,
playerId: undefined,
});
break;
default:
break;
}
};

const hideModal = () => {
setModalType(null);
};

React.useEffect(() => {
const handleEscape = (event: KeyboardEvent) => {
if (event.key === "Escape" && modalType) {
hideModal();
}
};

if (!deepEqual(props, payload)) {
setProps(payload);
}
}
document.addEventListener("keydown", handleEscape);

return () => {
document.removeEventListener("keydown", handleEscape);
};
}, [modalType, hideModal]);

function hideModal() {
setModal(false);
}
return (
<Provider value={{ showModal, hideModal }}>
{modal &&
{modalType &&
createPortal(
<div className="Modal-container">
<ChallengeModal {...props} />
{modalType === ModalTypes.Challenge && (
<ChallengeModal
{...(modalProps as Modals["challenge"])}
onClose={hideModal}
/>
)}
{modalType === ModalTypes.LanguagePicker && <LanguagePickerModal />}
</div>,
document.body,
)}
Expand Down
22 changes: 12 additions & 10 deletions src/views/Play/Play.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import {
timeControlSystemText,
usedForCheating,
} from "@/components/TimeControl";
import { challenge, challengeComputer } from "@/components/ChallengeModal";
import { challenge } from "@/components/ChallengeModal";
import { openGameAcceptModal } from "@/components/GameAcceptModal";
import { errorAlerter, rulesText, dup, uuid, ignore } from "@/lib/misc";
import { Player } from "@/components/Player";
Expand Down Expand Up @@ -380,14 +380,6 @@ export class Play extends React.Component<{}, PlayState> {
this.forceUpdate();
};

newComputerGame = () => {
if (bot_count() === 0) {
void alert.fire(_("Sorry, all bots seem to be offline, please try again later."));
return;
}
challengeComputer();
};

newCustomGame = () => {
challenge(undefined, undefined, undefined, undefined, this.challengeCreated);
};
Expand Down Expand Up @@ -834,7 +826,17 @@ export class Play extends React.Component<{}, PlayState> {
return (
<button
className="primary"
onClick={() => showModal(ModalTypes.Challenge)}
onClick={() => {
if (bot_count() === 0) {
void alert.fire(
_(
"Sorry, all bots seem to be offline, please try again later.",
),
);
return;
}
showModal(ModalTypes.Challenge);
}}
disabled={anon || warned}
>
<div className="play-button-text-root">
Expand Down

0 comments on commit 63bf5f2

Please sign in to comment.