Skip to content

Commit c821f07

Browse files
committed
Ability to remote start matches
1 parent 1bae856 commit c821f07

File tree

19 files changed

+194
-62
lines changed

19 files changed

+194
-62
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ A preview of major changes can be found in the Wiki ([Latest Changes](https://gi
44
## [2.9.0] - TBD
55
#### Feature
66
- Option to see `All` or `Unique` tournament statistics per player
7+
- Ability to "Remote Start" matches on a selected venue
78

89
#### Changed
910
- Updated to latest version of dependencies

app.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ app.locals.kcapp = {};
4545
app.locals.kcapp.api = process.env.KCAPP_API || 'http://localhost:8001';
4646
app.locals.kcapp.api_path = process.env.KCAPP_API_PATH || ':8001';
4747
app.locals.kcapp.local_admin = process.env.KCAPP_LOCAL_ADMIN ? process.env.KCAPP_LOCAL_ADMIN === "true" : true;
48+
app.locals.serializedGlobals = { kcapp: true };
4849

4950
// Create all routes
5051
const socketHandler = require('./routes/lib/socketio_handler')(io, app);
@@ -63,9 +64,6 @@ const venues = require('./routes/venues')(app, socketHandler);
6364
const badges = require('./routes/badges');
6465
socketHandler.setupActiveNamespace();
6566

66-
app.locals.moment = require('moment');
67-
app.locals._ = require('underscore');
68-
6967
// Write access log to a daily rotated file in /log
7068
const pad = num => (num > 9 ? "" : "0") + num;
7169
const generator = (time, index) => {

routes/lib/socketio_handler.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ module.exports = (io, app) => {
115115
nsp.on('connection', function (client) {
116116
const ip = getClientIP(client);
117117
debug("Client %s connected to '%s'", ip, namespace);
118+
119+
client.on('start_remote', (data) => {
120+
nsp.emit('start_remote', data);
121+
})
118122
});
119123
debug("Created socket.io namespace '%s'", namespace);
120124
}

routes/matches.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ router.post('/:id/rematch', function (req, res, next) {
337337

338338
/* Method for finishing a match */
339339
router.put('/:id/finish', function (req, res, next) {
340-
axios.put(`${req.app.locals.kcapp.api}/match/${req.params.id}`, req.body)
340+
axios.put(`${req.app.locals.kcapp.api}/match/${req.params.id}/score`, req.body)
341341
.then(response => {
342342
res.end();
343343
}).catch(error => {

routes/tournaments.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ router.post('/admin/generate', function (req, res, next) {
204204
const body = req.body;
205205

206206
const players = [];
207-
["group1", "group2", "group3", "group4"].forEach(key => {
207+
["group1", "group2", "group3", "group4", "group5", "group6", "group7", "group8"].forEach(key => {
208208
if (body[key]) {
209209
body[key].players.forEach(player => {
210210
players.push({
@@ -215,7 +215,7 @@ router.post('/admin/generate', function (req, res, next) {
215215
}
216216
});
217217
const venues = {};
218-
["group1", "group2", "group3", "group4"].forEach(key => {
218+
["group1", "group2", "group3", "group4", "group5", "group6", "group7", "group8"].forEach(key => {
219219
if (body[key]) {
220220
venues[body[key].group.id] = body[key].venueId;
221221
}
@@ -313,13 +313,14 @@ router.post('/:id/player', function (req, res, next) {
313313
router.get('/:id', function (req, res, next) {
314314
axios.all([
315315
axios.get(`${req.app.locals.kcapp.api}/player`),
316+
axios.get(`${req.app.locals.kcapp.api}/venue`),
316317
axios.get(`${req.app.locals.kcapp.api}/tournament/${req.params.id}`),
317318
axios.get(`${req.app.locals.kcapp.api}/tournament/${req.params.id}/overview`),
318319
axios.get(`${req.app.locals.kcapp.api}/tournament/${req.params.id}/matches`),
319320
axios.get(`${req.app.locals.kcapp.api}/tournament/${req.params.id}/statistics`),
320321
axios.get(`${req.app.locals.kcapp.api}/tournament/${req.params.id}/metadata`),
321322
axios.get(`${req.app.locals.kcapp.api}/match/modes`)
322-
]).then(axios.spread((playersResponse, tournamentResponse, overviewData, matchesData, statisticsResponse, metadataResponse, modesResponse) => {
323+
]).then(axios.spread((playersResponse, venueResponse, tournamentResponse, overviewData, matchesData, statisticsResponse, metadataResponse, modesResponse) => {
323324
const statistics = statisticsResponse.data;
324325
if (!_.isEmpty(statistics)) {
325326
statistics.checkout_highest = _.sortBy(statistics.checkout_highest, (stats) => -stats.value);
@@ -357,6 +358,7 @@ router.get('/:id', function (req, res, next) {
357358
playoffs_matches: playoffsMatches,
358359
statistics: statistics,
359360
modes: modesResponse.data,
361+
venues: venueResponse.data,
360362
});
361363
});
362364
})).catch(error => {
@@ -373,6 +375,7 @@ router.get('/:id', function (req, res, next) {
373375
matches: matches,
374376
statistics: statistics,
375377
modes: modesResponse.data,
378+
venues: venueResponse.data,
376379
});
377380
});
378381
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module.exports = {
22
onModalPressed(event) {
3-
this.emit('show-modal', this.input.data);
3+
this.emit('show-modal', this.input.data, this.input.modal);
44
}
55
}

src/components/matches-table/components/match-row/match-row.component.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ module.exports = {
1313
match: match
1414
}
1515
},
16-
onShowModal(matchId) {
17-
this.emit('show-modal', matchId);
16+
onShowModal(matchId, modal) {
17+
this.emit('show-modal', matchId, modal);
1818
}
1919
}

src/components/matches-table/components/match-row/match-row.marko

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ $ var columns = input.columns;
9292
<if(!match.has_scores)>
9393
<td class="text-center">
9494
<match-button title="View" icon="fa-cog" modal=`set-score-modal` data=match.id on-show-modal("onShowModal")/>
95-
</td>
95+
<match-button title="Start Remote" icon="fa-fast-forward" modal='start-remote-modal' data=match.id on-show-modal("onShowModal")/>
96+
</td>
9697
</if>
9798
<else>
9899
<td/>

src/components/matches-table/matches-table.component.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ module.exports = {
2727
columns: columns
2828
}
2929
},
30-
onShowModal(matchId) {
31-
this.emit('show-modal', matchId);
30+
onShowModal(matchId, modal) {
31+
this.emit('show-modal', matchId, modal);
3232
}
3333
}
Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1+
const axios = require('axios');
12
const localStorage = require('../../../../util/localstorage');
23

34
module.exports = {
4-
onCreate(input) {
5+
onCreate(input, out) {
56
this.state = {
67
layouts: [ {id: "wide", name: "Wide"}, {id: "compact", name: "Compact"}, {id: "compact-large", name: "Compact (Large)"} ],
78
buttonLayout: "wide",
89
volume: 100,
910
confirmBusts: true,
1011
autoFinishLegs: false,
11-
autoFinishTime: 10
12+
autoFinishTime: 10,
13+
remoteControl: false,
14+
venueId: -1,
15+
venues: [],
16+
locals: out.global.kcapp
1217
}
1318
},
1419
onMount() {
@@ -22,20 +27,30 @@ module.exports = {
2227
this.state.volume = Math.min(Math.max(parseInt(volume * 100), 0), 100);
2328
}
2429

25-
const confirmBusts = localStorage.get("confirm-busts");
26-
if (confirmBusts !== null) {
27-
this.state.confirmBusts = confirmBusts === 'true';
28-
}
29-
30-
const autoFinishLegs = localStorage.get("auto-finish-legs");
31-
if (autoFinishLegs !== null) {
32-
this.state.autoFinishLegs = autoFinishLegs === 'true';
33-
}
30+
this.state.confirmBusts = localStorage.getBool("confirm-busts", true);
31+
this.state.autoFinishLegs = localStorage.getBool("auto-finish-legs", false);
32+
this.state.remoteControl = localStorage.getBool("remote-control", false);
3433

3534
const autoFinishTime = localStorage.get("auto-finish-time");
3635
if (autoFinishTime !== null) {
3736
this.state.autoFinishTime = parseInt(autoFinishTime, 10) || 10;
3837
}
38+
39+
const venueId = localStorage.get('venue_id');
40+
if (venueId !== null) {
41+
this.state.venueId = parseInt(venueId);
42+
}
43+
44+
$(function() {
45+
$("#modal-configure-kcapp").on('shown.bs.modal', function(){
46+
axios.get(`${window.location.protocol}//${window.location.hostname}${this.state.locals.api_path}/venue`)
47+
.then(response => {
48+
this.state.venues = response.data;
49+
}).catch(error => {
50+
console.log('Error when getting venues ' + error);
51+
});
52+
}.bind(this));
53+
}.bind(this));
3954
},
4055
updateVolume(event, selected) {
4156
this.state.volume = selected.value;
@@ -46,15 +61,23 @@ module.exports = {
4661
toggleAutoFinishLegs(event) {
4762
this.state.autoFinishLegs = event.target.checked;
4863
},
64+
toggleRemoteControl(event) {
65+
this.state.remoteControl = event.target.checked;
66+
},
4967
updateAutoFinishTime(event) {
5068
this.state.autoFinishTime = parseInt(event.target.value, 10);
5169
},
5270
onSave() {
5371
this.state.buttonLayout = document.getElementById("buttonLayout").value;
5472
localStorage.set('button-layout', this.state.buttonLayout);
73+
74+
this.state.venueId = parseInt(document.getElementById("venueSelect").value);
75+
localStorage.set('venue_id', this.state.venueId);
76+
5577
localStorage.set('confirm-busts', this.state.confirmBusts);
5678
localStorage.set('auto-finish-legs', this.state.autoFinishLegs);
5779
localStorage.set('auto-finish-time', this.state.autoFinishTime);
5880
localStorage.set('volume', this.state.volume / 100);
81+
localStorage.set('remote-control', this.state.remoteControl);
5982
},
6083
}

src/components/navbar/components/configure-kcapp-modal/configure-kcapp-modal.marko

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<for|layout| of=state.layouts>
1616
<option style="text-transform: capitalize;" value=layout.id selected=(layout.id === state.buttonLayout)>${layout.name}</option>
1717
</for>
18-
</select>
18+
</select>
1919
</div>
2020
</div>
2121
</div>
@@ -59,6 +59,27 @@
5959
</div>
6060
</div>
6161
</div>
62+
<div>
63+
<div class="block-container-header">
64+
<span>Venue Options</span>
65+
</div>
66+
<div class="block-container-with-header">
67+
<div class="form-group form-check" style="margin-bottom: 1em;">
68+
<select id='venueSelect' class="form-select" style="width: 100%">
69+
<for|venue| of=state.venues>
70+
<option value=venue.id selected=(venue.id === state.venueId)>${venue.name}</option>
71+
</for>
72+
</select>
73+
</div>
74+
<div class="form-group form-check">
75+
<input type="checkbox" id="remoteControl" class="form-check-input" checked=state.remoteControl on-change("toggleRemoteControl")>
76+
<label class="toggle-button" for="remoteControl">
77+
<span class="toggle-slider"></span>
78+
</label>
79+
<span style="margin-left: 8px;">Remote Control</span>
80+
</div>
81+
</div>
82+
</div>
6283
</div>
6384
<div class="modal-footer">
6485
<button class="btn btn-primary" type="button" on-click("onSave") data-dismiss="modal">Save</button>

src/components/venue-socket/venue-socket.component.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ module.exports = {
88
}
99
},
1010
onMount() {
11-
const isController = localStorage.get('controller');
12-
const hasController = localStorage.get('has_controller');
13-
if (isController || hasController) {
11+
const isController = localStorage.getBool('controller', false);
12+
const hasController = localStorage.getBool('has_controller', false);
13+
const isRemote = localStorage.getBool('remote-control', false);
14+
if (isController || hasController || isRemote) {
1415
const venue = localStorage.get('venue_id');
1516
if (venue) {
1617
this.state.venueId = parseInt(venue);
@@ -29,6 +30,10 @@ module.exports = {
2930
}
3031
location.href = isController ? `/legs/${data.leg.id}/controller` : `/legs/${data.leg.id}`;
3132
});
33+
34+
socket.on('start_remote', (data) => {
35+
location.href = isController ? `/legs/${data.match.current_leg_id}/controller` : `/legs/${data.match.current_leg_id}`;
36+
});
3237
}
3338
}
3439
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
const io = require('../../../../../../util/socket.io-helper');
2+
const axios = require('axios');
3+
4+
module.exports = {
5+
onCreate(input, out) {
6+
this.state = {
7+
match: undefined,
8+
venueId: -1,
9+
locals: out.global.kcapp
10+
}
11+
},
12+
onMount() {
13+
$(function() {
14+
$("#start-remote-modal").on('shown.bs.modal', function(){
15+
const matchId = $("#start-remote-modal").data('matchId');
16+
if (matchId) {
17+
this.setMatch(matchId, true);
18+
}
19+
}.bind(this));
20+
}.bind(this));
21+
},
22+
onVenueChange(event) {
23+
this.state.venueId = parseInt(event.target.value);
24+
},
25+
setMatch(matchId, isBracket) {
26+
const match = this.input.matches[matchId];
27+
this.state.match = match;
28+
this.state.venueId = match.venue ? match.venue.id : -1;
29+
},
30+
startRemote(event) {
31+
const socket = io.connect(`${window.location.origin}/venue/${this.state.venueId}`);
32+
socket.on("connect", () => {
33+
const match = this.state.match;
34+
match.venue.id = this.state.venueId;
35+
36+
axios.put(`${window.location.protocol}//${window.location.hostname}${this.state.locals.api_path}/match/${match.id}`, match)
37+
.then(response => {
38+
this.state.venues = response.data;
39+
socket.emit('start_remote', { match: match });
40+
$("#start-remote-modal").modal('hide');
41+
}).catch(error => {
42+
console.log('Error when updating match ' + error);
43+
alert(`Error updating match ${error}`);
44+
});
45+
});
46+
event.preventDefault();
47+
}
48+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<div class="modal fade start-remote-modal" id=`start-remote-modal` data-matchId="-1" tabindex="-1" role="dialog" aria-labelledby=`start-remote-modal-label`>
2+
<div class="modal-dialog" role="document">
3+
<div class="block-container-header">
4+
<i class="fas fa-user-plus"/>
5+
<span class="ml-10">Start Remote</span>
6+
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
7+
<span aria-hidden="true">&times;</span>
8+
</button>
9+
</div>
10+
<div class="block-container-with-header">
11+
<form>
12+
<select class="form-control" onChange("onVenueChange")>
13+
<for|venue| of=input.venues>
14+
<option value=venue.id selected=(venue.id === state.venueId)>${venue.name}</option>
15+
</for>
16+
</select>
17+
<button class="btn btn-primary btn-submit mt-10" type="submit" on-click("startRemote")>
18+
<i class="fas fa-user-plus"/>
19+
<span class="ml-10">Start Remote</span>
20+
</button>
21+
</form>
22+
</div>
23+
</div>
24+
</div>

src/pages/tournament/components/tournament/tournament.component.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ module.exports = {
3131
}, {}));
3232
}
3333

34-
35-
3634
this.state = {
3735
hasStatistics: !_.isEmpty(input.statistics.best_three_dart_avg),
3836
matches: matches,
@@ -91,8 +89,8 @@ module.exports = {
9189
}
9290
});
9391
},
94-
onShowModal(matchId) {
95-
this.getComponent('set-score-modal').setMatch(matchId);
92+
onShowModal(matchId, modal) {
93+
this.getComponent(modal).setMatch(matchId);
9694
},
9795
onUpdatePredictions(groupId, overview) {
9896
const comp = this.getComponent(`predictor-overview-${groupId}`);
@@ -102,6 +100,5 @@ module.exports = {
102100
this.state.showAllStats = value;
103101
this.state.statistics = value ? this.input.statistics : this.state.unq_statistics;
104102
this.setStateDirty("statistics");
105-
console.log(this.state.statistics);
106103
}
107104
}

0 commit comments

Comments
 (0)