Improve games/challenges display and fix MyGames page reactivity (using () for now...)
[vchess.git] / client / src / views / MyGames.vue
CommitLineData
afd3240d
BA
1<template lang="pug">
2main
3 .row
4 .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
5 .button-group
910d631b
BA
6 button.tabbtn#liveGames(@click="setDisplay('live',$event)")
7 | {{ st.tr["Live games"] }}
8 button.tabbtn#corrGames(@click="setDisplay('corr',$event)")
9 | {{ st.tr["Correspondance games"] }}
10 GameList(
585d0955 11 ref="livegames"
910d631b
BA
12 v-show="display=='live'"
13 :games="liveGames"
14 @show-game="showGame"
3b0f26c1 15 @abortgame="abortGame"
910d631b
BA
16 )
17 GameList(
585d0955 18 ref="corrgames"
910d631b
BA
19 v-show="display=='corr'"
20 :games="corrGames"
21 @show-game="showGame"
3b0f26c1 22 @abortgame="abortGame"
910d631b 23 )
afd3240d
BA
24</template>
25
26<script>
afd3240d
BA
27import { store } from "@/store";
28import { GameStorage } from "@/utils/gameStorage";
29import { ajax } from "@/utils/ajax";
aae89b49 30import { getScoreMessage } from "@/utils/scoring";
23ecf008
BA
31import params from "@/parameters";
32import { getRandString } from "@/utils/alea";
afd3240d
BA
33import GameList from "@/components/GameList.vue";
34export default {
89021f18 35 name: "my-my-games",
afd3240d 36 components: {
6808d7a1 37 GameList
afd3240d
BA
38 },
39 data: function() {
40 return {
41 st: store.state,
dac39588 42 display: "live",
2f258c37 43 liveGames: [],
db1f1f9a
BA
44 corrGames: [],
45 conn: null,
46 connexionString: ""
afd3240d
BA
47 };
48 },
49 created: function() {
db1f1f9a
BA
50 // Initialize connection
51 this.connexionString =
52 params.socketUrl +
53 "/?sid=" +
54 this.st.user.sid +
cafe0166
BA
55 "&id=" +
56 this.st.user.id +
db1f1f9a
BA
57 "&tmpId=" +
58 getRandString() +
59 "&page=" +
60 encodeURIComponent(this.$route.path);
61 this.conn = new WebSocket(this.connexionString);
62 this.conn.onmessage = this.socketMessageListener;
63 this.conn.onclose = this.socketCloseListener;
afd3240d 64 },
2f258c37 65 mounted: function() {
585d0955
BA
66 const adjustAndSetDisplay = () => {
67 // showType is the last type viwed by the user (default)
68 let showType = localStorage.getItem("type-myGames") || "live";
69 // Live games, my turn: highest priority:
70 if (this.liveGames.some(g => !!g.myTurn)) showType = "live";
71 // Then corr games, my turn:
72 else if (this.corrGames.some(g => !!g.myTurn)) showType = "corr";
73 else {
74 // If a listing is empty, try showing the other (if non-empty)
75 const types = ["corr", "live"];
76 for (let i of [0,1]) {
77 if (
78 this[types[i] + "Games"].length > 0 &&
79 this[types[1-i] + "Games"].length == 0
80 ) {
81 showType = types[i];
82 }
83 }
84 }
85 this.setDisplay(showType);
86 };
87 GameStorage.getAll(localGames => {
88 localGames.forEach(g => g.type = "live");
89 this.decorate(localGames);
90 this.liveGames = localGames;
91 if (this.st.user.id > 0) {
92 ajax(
93 "/games",
94 "GET",
95 {
96 data: { uid: this.st.user.id },
97 success: (res) => {
98 let serverGames = res.games.filter(g => {
99 const mySide =
100 g.players[0].uid == this.st.user.id
101 ? "White"
102 : "Black";
103 return !g["deletedBy" + mySide];
104 });
105 serverGames.forEach(g => g.type = "corr");
106 this.decorate(serverGames);
107 this.corrGames = serverGames;
108 adjustAndSetDisplay();
109 }
110 }
111 );
112 } else adjustAndSetDisplay();
113 });
2f258c37 114 },
23ecf008
BA
115 beforeDestroy: function() {
116 this.conn.send(JSON.stringify({code: "disconnect"}));
117 },
afd3240d 118 methods: {
2f258c37
BA
119 setDisplay: function(type, e) {
120 this.display = type;
121 localStorage.setItem("type-myGames", type);
6808d7a1 122 let elt = e ? e.target : document.getElementById(type + "Games");
2f258c37 123 elt.classList.add("active");
23ecf008 124 elt.classList.remove("somethingnew"); //in case of
6808d7a1 125 if (elt.previousElementSibling)
2f258c37 126 elt.previousElementSibling.classList.remove("active");
6808d7a1 127 else elt.nextElementSibling.classList.remove("active");
2f258c37 128 },
cafe0166
BA
129 tryShowNewsIndicator: function(type) {
130 if (
131 (type == "live" && this.display == "corr") ||
132 (type == "corr" && this.display == "live")
133 ) {
134 document
135 .getElementById(type + "Games")
136 .classList.add("somethingnew");
137 }
138 },
28b32b4f 139 // Called at loading to augment games with myColor + myTurn infos
e727fe31
BA
140 decorate: function(games) {
141 games.forEach(g => {
6b7b2cf7
BA
142 g.myColor =
143 (g.type == "corr" && g.players[0].uid == this.st.user.id) ||
144 (g.type == "live" && g.players[0].sid == this.st.user.sid)
145 ? 'w'
146 : 'b';
147 // If game is over, myTurn doesn't exist:
e727fe31 148 if (g.score == "*") {
e727fe31 149 const rem = g.movesCount % 2;
6b7b2cf7 150 if ((rem == 0 && g.myColor == 'w') || (rem == 1 && g.myColor == 'b'))
e727fe31 151 g.myTurn = true;
e727fe31
BA
152 }
153 });
154 },
cafe0166
BA
155 socketMessageListener: function(msg) {
156 const data = JSON.parse(msg.data);
e727fe31
BA
157 let gamesArrays = {
158 "corr": this.corrGames,
159 "live": this.liveGames
160 };
cafe0166 161 switch (data.code) {
cafe0166
BA
162 case "notifyturn":
163 case "notifyscore": {
164 const info = data.data;
e727fe31
BA
165 const type = (!!parseInt(info.gid) ? "corr" : "live");
166 let game = gamesArrays[type].find(g => g.id == info.gid);
cafe0166
BA
167 // "notifything" --> "thing":
168 const thing = data.code.substr(6);
e727fe31 169 game[thing] = info[thing];
585d0955
BA
170 if (thing == "turn") {
171 game.myTurn = !game.myTurn;
172 if (game.myTurn) this.tryShowNewsIndicator(type);
173 }
174 // TODO: forcing refresh like that is ugly and wrong.
175 // How to do it cleanly?
176 this.$refs[type + "games"].$forceUpdate();
cafe0166
BA
177 break;
178 }
179 case "notifynewgame": {
180 const gameInfo = data.data;
181 // st.variants might be uninitialized,
182 // if unlucky and newgame right after connect:
183 const v = this.st.variants.find(v => v.id == gameInfo.vid);
184 const vname = !!v ? v.name : "";
e727fe31
BA
185 const type = (gameInfo.cadence.indexOf('d') >= 0 ? "corr": "live");
186 let game = Object.assign(
cafe0166
BA
187 {
188 vname: vname,
189 type: type,
2a8a94c9 190 score: "*",
e727fe31 191 created: Date.now()
cafe0166
BA
192 },
193 gameInfo
194 );
28b32b4f 195 game.myTurn =
e727fe31 196 (type == "corr" && game.players[0].uid == this.st.user.id) ||
28b32b4f 197 (type == "live" && game.players[0].sid == this.st.user.sid);
e727fe31 198 gamesArrays[type].push(game);
585d0955
BA
199 if (game.myTurn) this.tryShowNewsIndicator(type);
200 // TODO: cleaner refresh
201 this.$refs[type + "games"].$forceUpdate();
cafe0166
BA
202 break;
203 }
204 }
205 },
206 socketCloseListener: function() {
207 this.conn = new WebSocket(this.connexionString);
208 this.conn.addEventListener("message", this.socketMessageListener);
209 this.conn.addEventListener("close", this.socketCloseListener);
afd3240d 210 },
feaf1bf7 211 showGame: function(game) {
e727fe31 212 if (game.type == "live" || !game.myTurn) {
feaf1bf7 213 this.$router.push("/game/" + game.id);
620a88ed
BA
214 return;
215 }
feaf1bf7
BA
216 // It's my turn in this game. Are there others?
217 let nextIds = "";
e727fe31
BA
218 let otherCorrGamesMyTurn = this.corrGames.filter(g =>
219 g.id != game.id && !!g.myTurn);
feaf1bf7
BA
220 if (otherCorrGamesMyTurn.length > 0) {
221 nextIds += "/?next=[";
222 otherCorrGamesMyTurn.forEach(g => { nextIds += g.id + ","; });
223 // Remove last comma and close array:
224 nextIds = nextIds.slice(0, -1) + "]";
225 }
226 this.$router.push("/game/" + game.id + nextIds);
db1f1f9a 227 },
aae89b49
BA
228 abortGame: function(game) {
229 // Special "trans-pages" case: from MyGames to Game
230 // TODO: also for corr games? (It's less important)
231 if (game.type == "live") {
232 const oppsid =
233 game.players[0].sid == this.st.user.sid
234 ? game.players[1].sid
235 : game.players[0].sid;
236 this.conn.send(
237 JSON.stringify(
238 {
239 code: "mabort",
240 gid: game.id,
241 // NOTE: target might not be online
242 target: oppsid
243 }
244 )
245 );
246 }
247 else if (!game.deletedByWhite || !game.deletedByBlack) {
248 // Set score if game isn't deleted on server:
249 ajax(
250 "/games",
251 "PUT",
252 {
e57c4de4
BA
253 data: {
254 gid: game.id,
255 newObj: {
256 score: "?",
257 scoreMsg: getScoreMessage("?")
258 }
aae89b49
BA
259 }
260 }
261 );
262 }
6808d7a1
BA
263 }
264 }
afd3240d
BA
265};
266</script>
2f258c37 267
e2590fa8 268<style lang="sass">
2f258c37
BA
269.active
270 color: #42a983
5fe7e71c
BA
271
272.tabbtn
273 background-color: #f9faee
e2590fa8
BA
274
275table.game-list
276 max-height: 100%
23ecf008
BA
277
278.somethingnew
279 background-color: #c5fefe !important
2f258c37 280</style>