From 4161d552baad7b5175ed159ce4fb7f54ac07ac12 Mon Sep 17 00:00:00 2001 From: Halit Aksoy Date: Sat, 3 Sep 2022 21:03:30 +0300 Subject: [PATCH 01/20] remove user icon --- src/components/UserStatus.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/UserStatus.tsx b/src/components/UserStatus.tsx index 20b061b..8481544 100644 --- a/src/components/UserStatus.tsx +++ b/src/components/UserStatus.tsx @@ -22,10 +22,6 @@ const UserStatus: FunctionComponent<{ ); return (
- - face_6 - - {user.isAnonymous ? context.texts.Anonymous : user.name}
From 3344439ef43e03129cf0db8282ba831c4627b3e3 Mon Sep 17 00:00:00 2001 From: Halit Aksoy Date: Sat, 3 Sep 2022 21:06:52 +0300 Subject: [PATCH 02/20] fix info panel visible issue in mobile --- src/routes/GamePage.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/routes/GamePage.tsx b/src/routes/GamePage.tsx index 6ec6e64..45dd7c5 100644 --- a/src/routes/GamePage.tsx +++ b/src/routes/GamePage.tsx @@ -263,7 +263,7 @@ const GamePage: FunctionComponent<{ function renderMobileBoardToolbar() { return - {buildInfoPanel()} + {buildInfoPanel({ visible: isMobile })} ; } @@ -273,7 +273,7 @@ const GamePage: FunctionComponent<{ marginBottom: "0.5rem", marginLeft: "6%", maxWidth: isMobile ? "40vw" : "30vw", width: isMobile ? "40vw" : "30vw" }} context={context} layoutMode="left" user={topLocatedUser} visible={showBoardView || false} /> - {buildInfoPanel()} + {buildInfoPanel({ visible: !isMobile })} ; } - function buildInfoPanel() { + function buildInfoPanel(params: { visible: boolean }) { return ( ); } From 1a305dc74c7913f99a148d4cbd497892022d0740 Mon Sep 17 00:00:00 2001 From: Halit Aksoy Date: Sat, 3 Sep 2022 21:13:25 +0300 Subject: [PATCH 03/20] fix SwitchThemeMenu issues --- src/components/headerbar/ThemeSwitchMenu.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/headerbar/ThemeSwitchMenu.tsx b/src/components/headerbar/ThemeSwitchMenu.tsx index 73cb535..2934aeb 100644 --- a/src/components/headerbar/ThemeSwitchMenu.tsx +++ b/src/components/headerbar/ThemeSwitchMenu.tsx @@ -8,18 +8,17 @@ import "@szhsin/react-menu/dist/transitions/slide.css" const ThemeSwitchMenu: FunctionComponent<{ context: Context, textColor: string }> = (props) => { const { context, textColor } = props; const menuButton = light_mode ; const menuItems = context.themeManager.themes.map((theme, index) => { - const themeBackground = context.themeManager.theme.background; return ( (event.target.style.background = themeBackground)} + onMouseOver={(event) => (event.target.style.background = "transparent")} //@ts-ignore onMouseOut={(event) => (event.target.style.background = "transparent")} onClick={() => (context.themeManager.theme = theme)}> From ce4aab7c09c3272e7fa93334f6f9b3dc4e9c46d3 Mon Sep 17 00:00:00 2001 From: Halit Aksoy Date: Sat, 3 Sep 2022 21:24:52 +0300 Subject: [PATCH 04/20] add themePreviewColor to theme --- src/theme/DarkTheme.ts | 1 + src/theme/GreyTheme.ts | 1 + src/theme/LightTheme.ts | 1 + src/theme/Theme.ts | 1 + 4 files changed, 4 insertions(+) diff --git a/src/theme/DarkTheme.ts b/src/theme/DarkTheme.ts index 1a081c9..625aff2 100644 --- a/src/theme/DarkTheme.ts +++ b/src/theme/DarkTheme.ts @@ -13,6 +13,7 @@ const colorSpecial = "#337a44"; const darkTheme: Theme = { id: "2", name: "Dark Theme", + themePreviewColor: colors.primary, background: colors.primary, appBarBgColor: colors.secondary, textColor: colors.primary, diff --git a/src/theme/GreyTheme.ts b/src/theme/GreyTheme.ts index f8b4a80..448e8c9 100644 --- a/src/theme/GreyTheme.ts +++ b/src/theme/GreyTheme.ts @@ -3,6 +3,7 @@ import { Theme } from "./Theme"; const greyTheme: Theme = { id: "1", name: "Grey Theme", + themePreviewColor: "#4D606E", background: "#EEEEEE", appBarBgColor: "#e4e4e4", textColor: "#4D606E", diff --git a/src/theme/LightTheme.ts b/src/theme/LightTheme.ts index bdcbbdf..e81d5e4 100644 --- a/src/theme/LightTheme.ts +++ b/src/theme/LightTheme.ts @@ -5,6 +5,7 @@ const colorSpecial = "#8B8B8B"; const lightTheme: Theme = { id: "1", name: "Light Theme", + themePreviewColor: "#9B9B9B", background: "#BBBBBB", appBarBgColor: "#7B7B7B", textColor: "#5B5B5B", diff --git a/src/theme/Theme.ts b/src/theme/Theme.ts index b4067e0..11fa3f6 100644 --- a/src/theme/Theme.ts +++ b/src/theme/Theme.ts @@ -1,6 +1,7 @@ export type Theme = { id: string; name: string; + themePreviewColor: string; // for theme switch menu textColor: string; textLightColor: string; background: string; From 40118990a719e8878bf3de170351f36f32836eae Mon Sep 17 00:00:00 2001 From: Halit Aksoy Date: Sat, 3 Sep 2022 21:25:10 +0300 Subject: [PATCH 05/20] user themePreviewColor in ThemeSwitchMenu --- src/components/headerbar/ThemeSwitchMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/headerbar/ThemeSwitchMenu.tsx b/src/components/headerbar/ThemeSwitchMenu.tsx index 2934aeb..4d31ad9 100644 --- a/src/components/headerbar/ThemeSwitchMenu.tsx +++ b/src/components/headerbar/ThemeSwitchMenu.tsx @@ -22,7 +22,7 @@ const ThemeSwitchMenu: FunctionComponent<{ context: Context, textColor: string } //@ts-ignore onMouseOut={(event) => (event.target.style.background = "transparent")} onClick={() => (context.themeManager.theme = theme)}> -
+
{theme.name} {text} diff --git a/src/components/CircularPanel.tsx b/src/components/CircularPanel.tsx index 83d7dec..44ce01b 100644 --- a/src/components/CircularPanel.tsx +++ b/src/components/CircularPanel.tsx @@ -11,6 +11,7 @@ const CircularPanel: FunctionComponent<{ div { padding: 10px 20px; border-radius: 30px; + transition: background-color 0.5s; } `} diff --git a/src/components/InfoPanel.tsx b/src/components/InfoPanel.tsx index 5ccbafc..59545fb 100644 --- a/src/components/InfoPanel.tsx +++ b/src/components/InfoPanel.tsx @@ -99,7 +99,7 @@ const InfoPanel: FunctionComponent<{ if (text) { return ( -

+

{text}

diff --git a/src/components/PageContainer.tsx b/src/components/PageContainer.tsx index 82233f4..7d08f57 100644 --- a/src/components/PageContainer.tsx +++ b/src/components/PageContainer.tsx @@ -14,6 +14,7 @@ const PageContainer: FunctionComponent<{ theme: Theme }> = (props) => { align-items: center; flex: 1; min-height: 400px; + transition: background-color 0.5s; } `} {props.children} diff --git a/src/components/UserStatus.tsx b/src/components/UserStatus.tsx index 2a0489c..82882ff 100644 --- a/src/components/UserStatus.tsx +++ b/src/components/UserStatus.tsx @@ -22,7 +22,7 @@ const UserStatus: FunctionComponent<{ ); return (
- {user.isAnonymous ? context.texts.Anonymous : user.name} + {user.isAnonymous ? context.texts.Anonymous : user.name}
) diff --git a/src/components/headerbar/HeaderbarTitle.tsx b/src/components/headerbar/HeaderbarTitle.tsx index 2da3039..25174e5 100644 --- a/src/components/headerbar/HeaderbarTitle.tsx +++ b/src/components/headerbar/HeaderbarTitle.tsx @@ -4,7 +4,7 @@ import { Context } from '../../context/context'; const HeaderbarTitle: FunctionComponent<{ title: string, color: string }> = ({ title, color }) => { return ( -

+

{title} {text} From a82e8cedb048f254f949eb02e24202a67025906c Mon Sep 17 00:00:00 2001 From: Halit Aksoy Date: Sat, 3 Sep 2022 22:30:24 +0300 Subject: [PATCH 12/20] fix multiline issue in CircularPanel --- src/components/CircularPanel.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/CircularPanel.tsx b/src/components/CircularPanel.tsx index 44ce01b..2de9283 100644 --- a/src/components/CircularPanel.tsx +++ b/src/components/CircularPanel.tsx @@ -12,6 +12,7 @@ const CircularPanel: FunctionComponent<{ padding: 10px 20px; border-radius: 30px; transition: background-color 0.5s; + white-space: nowrap; } `} From 81365b835359d0ca500bc99357e02a649e67cd36 Mon Sep 17 00:00:00 2001 From: Halit Aksoy Date: Sat, 3 Sep 2022 23:12:45 +0300 Subject: [PATCH 13/20] add sweetalert --- package.json | 1 + yarn.lock | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/package.json b/package.json index 6326858..87909bb 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "react-dom": "^18.2.0", "react-router-dom": "6", "styled-jsx": "^5.0.2", + "sweetalert": "^2.1.2", "uuid": "^8.3.2" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index 34dbafb..b0f56f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1418,6 +1418,11 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +es6-object-assign@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" + integrity sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw== + escalade@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" @@ -1738,6 +1743,11 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== +promise-polyfill@^6.0.2: + version "6.1.0" + resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-6.1.0.tgz#dfa96943ea9c121fca4de9b5868cb39d3472e057" + integrity sha512-g0LWaH0gFsxovsU7R5LrrhHhWAWiHRnh1GPrhXnPgYsDkIqjRYUYSZEsej/wtleDrz5xVSIDbeKfidztp2XHFQ== + prop-types@^15.7.2: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" @@ -1884,6 +1894,14 @@ svgo@^2.4.0, svgo@^2.5.0: picocolors "^1.0.0" stable "^0.1.8" +sweetalert@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/sweetalert/-/sweetalert-2.1.2.tgz#010baaa80d0dbdc86f96bfcaa96b490728594b79" + integrity sha512-iWx7X4anRBNDa/a+AdTmvAzQtkN1+s4j/JJRWlHpYE8Qimkohs8/XnFcWeYHH2lMA8LRCa5tj2d244If3S/hzA== + dependencies: + es6-object-assign "^1.1.0" + promise-polyfill "^6.0.2" + term-size@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" From 6d28d86a7ce8990d2ad52cb0e02b2c133409c1cb Mon Sep 17 00:00:00 2001 From: Halit Aksoy Date: Sat, 3 Sep 2022 23:27:13 +0300 Subject: [PATCH 14/20] add alert for userkey error --- src/MancalaApp.tsx | 15 +++++++++++---- src/const/texts.ts | 6 ++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/MancalaApp.tsx b/src/MancalaApp.tsx index 03b46a4..0dd1c4f 100644 --- a/src/MancalaApp.tsx +++ b/src/MancalaApp.tsx @@ -15,6 +15,8 @@ import { getColorByBrightness } from './util/ColorUtil'; import { ConnectionState } from './models/ConnectionState'; import { Theme } from './theme/Theme'; import LobyPage from './routes/LobyPage'; +import swal from 'sweetalert'; + const context = initContext(); const MancalaApp: FunctionComponent = () => { @@ -40,9 +42,15 @@ const MancalaApp: FunctionComponent = () => { setTheme(theme) } const connectToServer = async () => { - const userKey = await context.userKeyStore.getUserKey(); - setUserKey(userKey); - (context.rtmt as RTMTWS).initWebSocket(userKey); + try { + const userKey = await context.userKeyStore.getUserKey(); + setUserKey(userKey); + (context.rtmt as RTMTWS).initWebSocket(userKey); + } catch (error) { + //TODO: check if it is network error! + swal(context.texts.Error + "!", context.texts.ErrorWhenRetrievingInformation, "error"); + console.error(error); + } }; React.useEffect(() => { @@ -74,7 +82,6 @@ const MancalaApp: FunctionComponent = () => { context.themeManager.theme.textColor, context.themeManager.theme.textLightColor ); - if (!userKey) return <>; return ( <> diff --git a/src/const/texts.ts b/src/const/texts.ts index cf8cfce..7065ffc 100644 --- a/src/const/texts.ts +++ b/src/const/texts.ts @@ -27,6 +27,8 @@ export type Texts = { GameNotFound: string, Loading: string, Playing: string, + Error: string, + ErrorWhenRetrievingInformation: string; } export const EnUs: Texts = { @@ -57,6 +59,8 @@ export const EnUs: Texts = { GameNotFound: "Game Not Found", Loading: "Loading", Playing: "Playing", + Error: "Error", + ErrorWhenRetrievingInformation: "An error occured when retrieving information!" } export const TrTr: Texts = { @@ -87,4 +91,6 @@ export const TrTr: Texts = { GameNotFound: "Oyun Bulunamadı", Loading: "Yükleniyor", Playing: "Oynuyor", + Error: "Hata", + ErrorWhenRetrievingInformation: "Bilgiler toplanırken bir hata oluştu!" } \ No newline at end of file From 8f6870c6ffbef6d6247850cacfe628cb63f43337 Mon Sep 17 00:00:00 2001 From: Halit Aksoy Date: Sat, 3 Sep 2022 23:28:14 +0300 Subject: [PATCH 15/20] fix typo --- src/MancalaApp.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MancalaApp.tsx b/src/MancalaApp.tsx index 0dd1c4f..d7e5881 100644 --- a/src/MancalaApp.tsx +++ b/src/MancalaApp.tsx @@ -97,7 +97,7 @@ const MancalaApp: FunctionComponent = () => { - {connectionStateText()} + {connectionStateText()} ); From 9ab260a0a78274274f5d27e190bb6db943b689d1 Mon Sep 17 00:00:00 2001 From: Halit Aksoy Date: Sat, 3 Sep 2022 23:30:01 +0300 Subject: [PATCH 16/20] add notyf library --- package.json | 1 + yarn.lock | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/package.json b/package.json index 87909bb..b3b4f81 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@types/uuid": "^8.3.4", "eventemitter2": "^6.4.7", "mancala.js": "^0.0.2-beta.3", + "notyf": "^3.10.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "6", diff --git a/yarn.lock b/yarn.lock index b0f56f8..0bbdc99 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1635,6 +1635,11 @@ node-releases@^2.0.6: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== +notyf@^3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/notyf/-/notyf-3.10.0.tgz#67a64443c69ea0e6495c56ea0f91198860163d06" + integrity sha512-Mtnp+0qiZxgrH+TzVlzhWyZceHdAZ/UWK0/ju9U0HQeDpap1mZ8cC7H5wSI5mwgni6yeAjaxsTw0sbMK+aSuHw== + nth-check@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" From 9ea7ecfe939154de129f35dfb8613f86165d8143 Mon Sep 17 00:00:00 2001 From: Halit Aksoy Date: Sun, 4 Sep 2022 00:04:32 +0300 Subject: [PATCH 17/20] notify user if is necessary --- src/const/texts.ts | 22 ++++++++++++++++------ src/routes/GamePage.tsx | 15 +++++++++++---- src/util/Notyf.ts | 4 ++++ 3 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 src/util/Notyf.ts diff --git a/src/const/texts.ts b/src/const/texts.ts index 7065ffc..13848fc 100644 --- a/src/const/texts.ts +++ b/src/const/texts.ts @@ -6,7 +6,7 @@ export type Texts = { YourTurn: string, OpponentTurn: string, GameEnded: string, - GameCrashed: string, + InternalErrorOccurred: string, YouWon: string, Won: string, YouLost: string, @@ -28,7 +28,10 @@ export type Texts = { Loading: string, Playing: string, Error: string, - ErrorWhenRetrievingInformation: string; + ErrorWhenRetrievingInformation: string, + UCanOnlyPlayYourOwnPits: string, + UMustWaitUntilCurrentMoveComplete: string, + UCanNotPlayEmptyPit: string, } export const EnUs: Texts = { @@ -38,7 +41,7 @@ export const EnUs: Texts = { YourTurn: "Your Turn", OpponentTurn: "Opponent Turn", GameEnded: "Game Ended", - GameCrashed: "Game Crashed", + InternalErrorOccurred: "An internal error has occurred", YouWon: "You Won", Won: "Won", YouLost: "You Lost", @@ -60,7 +63,11 @@ export const EnUs: Texts = { Loading: "Loading", Playing: "Playing", Error: "Error", - ErrorWhenRetrievingInformation: "An error occured when retrieving information!" + ErrorWhenRetrievingInformation: "An error occured when retrieving information!", + UCanOnlyPlayYourOwnPits: "You can only play your own pits", + UMustWaitUntilCurrentMoveComplete: "You must wait until the current move is complete", + UCanNotPlayEmptyPit: "You can not play empty pit", + } export const TrTr: Texts = { @@ -70,7 +77,7 @@ export const TrTr: Texts = { YourTurn: "Sıra Sende", OpponentTurn: "Sıra Rakipte", GameEnded: "Oyun Bitti", - GameCrashed: "Oyunda Hata Oluştu", + InternalErrorOccurred: "Dahili bir hata oluştu", YouWon: "Kazandın", Won: "Kazandı", YouLost: "Kaybettin", @@ -92,5 +99,8 @@ export const TrTr: Texts = { Loading: "Yükleniyor", Playing: "Oynuyor", Error: "Hata", - ErrorWhenRetrievingInformation: "Bilgiler toplanırken bir hata oluştu!" + ErrorWhenRetrievingInformation: "Bilgiler toplanırken bir hata oluştu!", + UCanOnlyPlayYourOwnPits: "Sadece sana ait olan kuyular ile oynayabilirsin", + UMustWaitUntilCurrentMoveComplete: "Devam eden haraketin bitmesini beklemelisin", + UCanNotPlayEmptyPit: "Boş kuyu ile oynayamazsın", } \ No newline at end of file diff --git a/src/routes/GamePage.tsx b/src/routes/GamePage.tsx index 45dd7c5..f1de1b5 100644 --- a/src/routes/GamePage.tsx +++ b/src/routes/GamePage.tsx @@ -28,6 +28,7 @@ import { getColorByBrightness } from '../util/ColorUtil'; import BoardViewModel from '../viewmodel/BoardViewModel'; import Center from '../components/Center'; import { Game, GameUsersConnectionInfo } from '../models/Game'; +import notyf from '../util/Notyf'; const GamePage: FunctionComponent<{ context: Context, @@ -89,6 +90,7 @@ const GamePage: FunctionComponent<{ } const onGameCrashed = (message: any) => { const newCrashMessage = message as string; + notyf.error(context.texts.InternalErrorOccurred); console.error("on_game_crash"); console.error(newCrashMessage); } @@ -147,21 +149,26 @@ const GamePage: FunctionComponent<{ if (!game || isSpectator || !userKey) { return; } + if(game.mancalaGame.getPlayerIdByIndex(index) !== userKey) { + notyf.error(context.texts.UCanOnlyPlayYourOwnPits); + return; + } const pitIndexForUser = index % (game.mancalaGame.board.totalPitCount() / 2); - if (game.mancalaGame.getPlayerIdByIndex(index) !== userKey || - !game.mancalaGame.canPlayerMove(userKey, pitIndexForUser)) { + if (!game.mancalaGame.canPlayerMove(userKey, pitIndexForUser)) { + notyf.error(context.texts.OpponentTurn); return; } if (checkHasAnOngoingAction()) { + notyf.error(context.texts.UMustWaitUntilCurrentMoveComplete); return; } - setHasOngoingAction(true); if (!boardViewModel) return; //TODO: this check should be in mancala.js if (pit.stoneCount === 0) { - //TODO : warn user + notyf.error(context.texts.UCanNotPlayEmptyPit); return; } + setHasOngoingAction(true); boardViewModel.pits[getBoardIndex(pitIndexForUser)].pitColor = context.themeManager.theme.pitSelectedColor; updateBoardViewModel(boardViewModel); diff --git a/src/util/Notyf.ts b/src/util/Notyf.ts new file mode 100644 index 0000000..753a1f7 --- /dev/null +++ b/src/util/Notyf.ts @@ -0,0 +1,4 @@ +import { Notyf } from 'notyf'; +import 'notyf/notyf.min.css'; +const notyf = new Notyf(); +export default notyf; \ No newline at end of file From 886852611b0f26bc51997acfa92772092cac8682 Mon Sep 17 00:00:00 2001 From: Halit Aksoy Date: Sun, 4 Sep 2022 00:16:14 +0300 Subject: [PATCH 18/20] add leave game dialog --- src/const/texts.ts | 20 ++++++++++++++------ src/routes/GamePage.tsx | 15 +++++++++++++-- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/const/texts.ts b/src/const/texts.ts index 13848fc..1f4b9dc 100644 --- a/src/const/texts.ts +++ b/src/const/texts.ts @@ -21,8 +21,8 @@ export type Texts = { YouLeftTheGame: string, UserLeftTheGame: string, SearchingOpponent: string, - PleaseWait : string, - GameDraw : string, + PleaseWait: string, + GameDraw: string, Anonymous: string, GameNotFound: string, Loading: string, @@ -32,6 +32,9 @@ export type Texts = { UCanOnlyPlayYourOwnPits: string, UMustWaitUntilCurrentMoveComplete: string, UCanNotPlayEmptyPit: string, + AreYouSureToLeaveGame: string, + Yes: string, + Cancel: string, } export const EnUs: Texts = { @@ -56,8 +59,8 @@ export const EnUs: Texts = { YouLeftTheGame: "You Left The Game", UserLeftTheGame: "Left The Game", SearchingOpponent: "Searching Opponent", - PleaseWait : "Please Wait", - GameDraw : "Draw", + PleaseWait: "Please Wait", + GameDraw: "Draw", Anonymous: "Anonymous", GameNotFound: "Game Not Found", Loading: "Loading", @@ -67,7 +70,9 @@ export const EnUs: Texts = { UCanOnlyPlayYourOwnPits: "You can only play your own pits", UMustWaitUntilCurrentMoveComplete: "You must wait until the current move is complete", UCanNotPlayEmptyPit: "You can not play empty pit", - + AreYouSureToLeaveGame: "Are you sure to leave game?", + Yes: "Yes", + Cancel: "Cancel", } export const TrTr: Texts = { @@ -93,7 +98,7 @@ export const TrTr: Texts = { UserLeftTheGame: "Oyundan Ayrıldı", SearchingOpponent: "Rakip Aranıyor", PleaseWait: "Lütfen Bekleyin", - GameDraw : "Berabere", + GameDraw: "Berabere", Anonymous: "Anonim", GameNotFound: "Oyun Bulunamadı", Loading: "Yükleniyor", @@ -103,4 +108,7 @@ export const TrTr: Texts = { UCanOnlyPlayYourOwnPits: "Sadece sana ait olan kuyular ile oynayabilirsin", UMustWaitUntilCurrentMoveComplete: "Devam eden haraketin bitmesini beklemelisin", UCanNotPlayEmptyPit: "Boş kuyu ile oynayamazsın", + AreYouSureToLeaveGame: "Oyundan ayrılmak istediğine emin misin?", + Yes: "Evet", + Cancel: "İptal" } \ No newline at end of file diff --git a/src/routes/GamePage.tsx b/src/routes/GamePage.tsx index f1de1b5..bdc2e2a 100644 --- a/src/routes/GamePage.tsx +++ b/src/routes/GamePage.tsx @@ -29,6 +29,7 @@ import BoardViewModel from '../viewmodel/BoardViewModel'; import Center from '../components/Center'; import { Game, GameUsersConnectionInfo } from '../models/Game'; import notyf from '../util/Notyf'; +import swal from 'sweetalert'; const GamePage: FunctionComponent<{ context: Context, @@ -138,7 +139,17 @@ const GamePage: FunctionComponent<{ const checkHasAnOngoingAction = () => hasOngoingAction; const onLeaveGameClick = () => { - context.rtmt.sendMessage(channel_leave_game, {}); + swal({ + title: context.texts.AreYouSureToLeaveGame, + icon: "warning", + buttons: [context.texts.Yes, context.texts.Cancel], + dangerMode: true, + }) + .then((cancel) => { + if (!cancel) { + context.rtmt.sendMessage(channel_leave_game, {}); + } + }); }; const onNewGameClick = () => { @@ -149,7 +160,7 @@ const GamePage: FunctionComponent<{ if (!game || isSpectator || !userKey) { return; } - if(game.mancalaGame.getPlayerIdByIndex(index) !== userKey) { + if (game.mancalaGame.getPlayerIdByIndex(index) !== userKey) { notyf.error(context.texts.UCanOnlyPlayYourOwnPits); return; } From 472044577fe4facec4ec5f65874c64f9432a4ff9 Mon Sep 17 00:00:00 2001 From: Halit Aksoy Date: Sun, 4 Sep 2022 01:06:07 +0300 Subject: [PATCH 19/20] move connection state to rtmt --- src/const/texts.ts | 4 ++-- src/models/ConnectionState.ts | 1 - src/rtmt/rtmt.ts | 2 ++ src/rtmt/rtmt_websocket.ts | 11 ++++++++++- src/util/Util.ts | 12 +++++++++++- 5 files changed, 25 insertions(+), 5 deletions(-) delete mode 100644 src/models/ConnectionState.ts diff --git a/src/const/texts.ts b/src/const/texts.ts index 1f4b9dc..273cc72 100644 --- a/src/const/texts.ts +++ b/src/const/texts.ts @@ -51,7 +51,7 @@ export const EnUs: Texts = { Connecting: "Connecting", Connected: "Connected", CannotConnect: "Can't Connect", - ConnectionLost: "Connection Lost", + ConnectionLost: "Network Connection Lost", ConnectingAgain: "Connecting Again", ServerError: "Server Error", SearchingOpponet: "Searching Opponet", @@ -89,7 +89,7 @@ export const TrTr: Texts = { Connecting: "Bağlanılıyor", Connected: "Bağlandı", CannotConnect: "Bağlanılamadı", - ConnectionLost: "Bağlantı Koptu", + ConnectionLost: "Ağ Bağlantısı Koptu", ConnectingAgain: "Tekrar Bağlanılıyor", ServerError: "Sunucu Hatası", SearchingOpponet: "Rakip Aranıyor", diff --git a/src/models/ConnectionState.ts b/src/models/ConnectionState.ts deleted file mode 100644 index 5010944..0000000 --- a/src/models/ConnectionState.ts +++ /dev/null @@ -1 +0,0 @@ -export type ConnectionState = "connecting" | "error" | "connected" | "reconnecting"; \ No newline at end of file diff --git a/src/rtmt/rtmt.ts b/src/rtmt/rtmt.ts index 4e5e010..499a8a0 100644 --- a/src/rtmt/rtmt.ts +++ b/src/rtmt/rtmt.ts @@ -3,10 +3,12 @@ import EventEmitter2, { Listener } from "eventemitter2" export type Bytes = Uint8Array export type OnMessage = (message : Object) => any +export type ConnectionState = "none" | "connecting" | "error" | "connected" | "closed" | "reconnecting"; export type RtmtEventTypes = "open" | "close" | "connected" | "error" | "disconnected" | "message"; export interface RTMT extends EventEmitter2 { + get connectionState() : ConnectionState; sendMessage: (channel: string, message: Object) => void; addMessageListener(channel: string, callback: (message: any) => void); removeMessageListener(channel: string, callback: (message: any) => void); diff --git a/src/rtmt/rtmt_websocket.ts b/src/rtmt/rtmt_websocket.ts index a60d2e4..2117618 100644 --- a/src/rtmt/rtmt_websocket.ts +++ b/src/rtmt/rtmt_websocket.ts @@ -2,7 +2,7 @@ import { decode, encode } from "./encode_decode_message"; import { channel_ping, channel_pong } from "../const/channel_names"; import { server } from "../const/config"; import EventEmitter2, { Listener } from "eventemitter2"; -import { Bytes, RTMT, RtmtEventTypes } from "./rtmt"; +import { Bytes, ConnectionState, RTMT, RtmtEventTypes } from "./rtmt"; const PING_INTERVAL = 15000, PING_INTERVAL_BUFFER_TIME = 1000; const MESSAGE_CHANNEL_PREFIX = "message_channel"; @@ -10,24 +10,32 @@ const MESSAGE_CHANNEL_PREFIX = "message_channel"; export class RTMTWS extends EventEmitter2 implements RTMT { private webSocket: WebSocket; private pingTimeout?: number = undefined; + private _connectionState: ConnectionState = "none"; constructor() { super(); } + get connectionState(): ConnectionState { + return this._connectionState; + } + public initWebSocket(userKey: string) { + this._connectionState = this._connectionState !== "none" ? "reconnecting" : "connecting"; const url = server.wsServerAdress + "?userKey=" + userKey; const webSocket = new WebSocket(url); webSocket.onopen = () => { console.info("(RTMT) WebSocket has opened"); this.webSocket = webSocket; this.heartbeat(); + this._connectionState = "connected"; this.emit("open"); }; webSocket.onclose = () => { console.info("(RTMT) WebSocket has closed"); //this.WebSocket = undefined clearTimeout(this.pingTimeout); + this._connectionState = "closed"; this.emit("close"); }; webSocket.onmessage = (event: MessageEvent) => { @@ -36,6 +44,7 @@ export class RTMTWS extends EventEmitter2 implements RTMT { }; webSocket.onerror = (error) => { console.error(error); + this._connectionState = "error"; this.emit("error", error); } } diff --git a/src/util/Util.ts b/src/util/Util.ts index 5898bbf..cf27332 100644 --- a/src/util/Util.ts +++ b/src/util/Util.ts @@ -1,10 +1,20 @@ +import { Context } from "../context/context"; +import notyf from "./Notyf"; export default class Util { public static range(size: number) { - var ans : number[] = []; + var ans: number[] = []; for (let i = 0; i < size; i++) { ans.push(i); } return ans; } + + public static checkConnectionAndMaybeAlert(context: Context): boolean { + if (context.rtmt.connectionState !== "connected") { + notyf.error(context.texts.ConnectionLost); + return true; + } + return false; + } } From 639cb942ef2065611bc784ccb487869253048eb8 Mon Sep 17 00:00:00 2001 From: Halit Aksoy Date: Sun, 4 Sep 2022 01:06:26 +0300 Subject: [PATCH 20/20] add checkConnectionAndMaybeAlert --- src/MancalaApp.tsx | 4 ++-- src/routes/GamePage.tsx | 12 +++++++----- src/routes/Home.tsx | 2 ++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/MancalaApp.tsx b/src/MancalaApp.tsx index d7e5881..b35675d 100644 --- a/src/MancalaApp.tsx +++ b/src/MancalaApp.tsx @@ -12,10 +12,10 @@ import Home from './routes/Home'; import { initContext } from './context/context'; import { RTMTWS } from './rtmt/rtmt_websocket'; import { getColorByBrightness } from './util/ColorUtil'; -import { ConnectionState } from './models/ConnectionState'; import { Theme } from './theme/Theme'; import LobyPage from './routes/LobyPage'; import swal from 'sweetalert'; +import { ConnectionState } from './rtmt/rtmt'; const context = initContext(); @@ -89,7 +89,7 @@ const MancalaApp: FunctionComponent = () => { } /> - } > + } > }> diff --git a/src/routes/GamePage.tsx b/src/routes/GamePage.tsx index bdc2e2a..331d841 100644 --- a/src/routes/GamePage.tsx +++ b/src/routes/GamePage.tsx @@ -20,7 +20,6 @@ import UserStatus from '../components/UserStatus'; import { channel_on_game_update, channel_on_game_crashed, channel_on_game_user_leave, channel_on_user_connection_change, channel_leave_game, channel_game_move, channel_listen_game_events, channel_unlisten_game_events } from '../const/channel_names'; import { Context } from '../context/context'; import useWindowDimensions from '../hooks/useWindowDimensions'; -import { ConnectionState } from '../models/ConnectionState'; import { GameMove } from '../models/GameMove'; import { LoadingState } from '../models/LoadingState'; import { Theme } from '../theme/Theme'; @@ -30,13 +29,13 @@ import Center from '../components/Center'; import { Game, GameUsersConnectionInfo } from '../models/Game'; import notyf from '../util/Notyf'; import swal from 'sweetalert'; +import Util from '../util/Util'; const GamePage: FunctionComponent<{ context: Context, userKey?: string, theme: Theme, - connectionState: ConnectionState -}> = ({ context, userKey, theme, connectionState }) => { +}> = ({ context, userKey, theme }) => { let params = useParams<{ gameId: string }>(); const [game, setGame] = useState(undefined); @@ -139,6 +138,7 @@ const GamePage: FunctionComponent<{ const checkHasAnOngoingAction = () => hasOngoingAction; const onLeaveGameClick = () => { + if(Util.checkConnectionAndMaybeAlert(context)) return; swal({ title: context.texts.AreYouSureToLeaveGame, icon: "warning", @@ -153,6 +153,7 @@ const GamePage: FunctionComponent<{ }; const onNewGameClick = () => { + if(Util.checkConnectionAndMaybeAlert(context)) return; navigate("/loby") }; @@ -173,6 +174,7 @@ const GamePage: FunctionComponent<{ notyf.error(context.texts.UMustWaitUntilCurrentMoveComplete); return; } + if(Util.checkConnectionAndMaybeAlert(context)) return; if (!boardViewModel) return; //TODO: this check should be in mancala.js if (pit.stoneCount === 0) { @@ -228,13 +230,13 @@ const GamePage: FunctionComponent<{ const bottomLocatedUser = { id: bottomLocatedUserId, name: "Anonymous", - isOnline: isSpectator ? isUserOnline(bottomLocatedUserId) : connectionState === "connected", + isOnline: isSpectator ? isUserOnline(bottomLocatedUserId) : context.rtmt.connectionState === "connected", isAnonymous: true }; const currentUser = isSpectator ? { id: "2", name: "Anonymous", - isOnline: connectionState === "connected", + isOnline: context.rtmt.connectionState === "connected", isAnonymous: true } : bottomLocatedUser; const leftPlayer = userKeyWhoLeave ? (userKeyWhoLeave === topLocatedUser.id ? topLocatedUser : bottomLocatedUser) : undefined; diff --git a/src/routes/Home.tsx b/src/routes/Home.tsx index c37b345..268589c 100644 --- a/src/routes/Home.tsx +++ b/src/routes/Home.tsx @@ -11,6 +11,7 @@ import ThemeSwitchMenu from "../components/headerbar/ThemeSwitchMenu"; import Button from "../components/Button"; import { Context } from "../context/context"; import { Link, useNavigate } from "react-router-dom"; +import Util from "../util/Util"; const Home: FunctionComponent<{ context: Context, @@ -21,6 +22,7 @@ const Home: FunctionComponent<{ const navigate = useNavigate(); const onNewGameClick = () => { + if(Util.checkConnectionAndMaybeAlert(context)) return; navigate("/loby") };