Teams handing in progress

This commit is contained in:
Claude Brisson
2024-04-15 16:33:17 +02:00
parent 2395c4e071
commit 179a502bbc
20 changed files with 249 additions and 68 deletions

View File

@@ -97,4 +97,11 @@ class PairgothTool {
}
fun getRatingsDates() = RatingsManager.getRatingsDates()
fun getTeamables(players: Collection<Json.Object>, teams: Collection<Json.Object>): List<Json.Object> {
val teamed = teams.flatMap { team ->
team.getArray("players")!!.map { it -> it as Long }
}.toSet()
return players.filter { p -> !teamed.contains(p.getLong("id")) }
}
}

View File

@@ -237,6 +237,45 @@
}
}
/* teams section */
#teams-content {
display: flex;
flex-flow: column;
justify-content: start;
align-items: center;
}
#teams-lists {
margin-top: 1em;
flex-grow: 2;
display: flex;
flex-flow: row wrap;
justify-content: center;
gap: 1em;
align-items: start;
}
#teams-buttons {
display: flex;
flex-flow: column nowrap;
justify-content: start;
align-items: stretch;
gap: 1em;
max-width: max(10em, 20vw);
}
#teams-right {
display: inline-flex;
flex-flow: row wrap;
gap: 1em;
flex-shrink: 1;
max-width: max(300px, 60vw);
justify-content: center;
}
#teams {
max-width: max(50vw, 20em);
}
/* pairing section */
#pairing-content {
@@ -428,7 +467,7 @@
}
}
@media(max-width: 1400px) {
@media(max-width: 1600px) {
.ui.steps > .step:not(.active) {
padding-left: 1.2em;
padding-right: 0.8em;

View File

@@ -81,36 +81,43 @@ function updatePairable() {
}
onLoad(()=>{
// note - this handler is also in use for lists on Mac Mahon super groups and teams pages
$('.listitem').on('click', e => {
let listitem = e.target.closest('.listitem');
let box = e.target.closest('.multi-select');
if (e.shiftKey && typeof(focused) !== 'undefined') {
let from = focused.index('.listitem');
let to = e.target.closest('.listitem').index('.listitem');
let to = listitem.index('.listitem');
if (from > to) {
let tmp = from;
from = to;
to = tmp;
}
let parent = e.target.closest('.multi-select');
let children = parent.childNodes.filter('.listitem');
let children = box.childNodes.filter('.listitem');
for (let j = from; j <= to; ++j) { new Tablesort($('#players')[0]);
children.item(j).addClass('selected');
children.item(j).attr('draggable', true);
}
} else {
let target = e.target.closest('.listitem');
if (e.detail === 1) {
focused = target.toggleClass('selected').attr('draggable', target.hasClass('selected'));
} else if (target.closest('#paired')) {
focused = target.attr('draggable', target.hasClass('selected'));
editGame(focused);
} else {
editPairable(focused);
// single click
focused = listitem.toggleClass('selected').attr('draggable', listitem.hasClass('selected'));
} else if (listitem.closest('#pairing-lists')) {
// on pairing page
if (listitem.closest('#paired')) {
// double click
focused = listitem.attr('draggable', listitem.hasClass('selected'));
editGame(focused);
} else if (listitem.closest('#pairables')) {
editPairable(focused);
}
}
}
box.dispatchEvent(new CustomEvent('listitems'));
});
$('#pair').on('click', e => {
let parts = $('#pairables .selected.listitem').map(item => parseInt(item.data("id")));
if (parts.length == 0) {
if (parts.length) {
$('#pairables .listitem').addClass('selected');
parts = $('#pairables .selected.listitem').map(item => parseInt(item.data("id")));
}

View File

@@ -0,0 +1,44 @@
function teamUp(players) {
api.postJson(`tour/${tour_id}/team`, {
"name": $('#team-name')[0].value,
"players": players
}).then(rst => {
if (rst !== 'error') {
document.location.reload();
}
});
}
function split(teams) {
let promises = teams.map(team => api.deleteJson(`tour/${tour_id}/team/${team}`));
Promise.all(promises)
.then(rsts => {
for (let rst of rsts) {
if (!rst.success) console.error(rst.error)
}
document.location.reload();
});
}
onLoad(() => {
$('#teamup').on('click', e => {
let rows = $('#teamables .selected.listitem')
let players = rows.map(item => parseInt(item.data("id")));
if (players.length !== 0) teamUp(players);
});
$('#split').on('click', e => {
let rows = $('#teams .selected.listitem')
let teams = rows.map(item => parseInt(item.data("id")));
if (teams.length !== 0) split(teams);
});
$('#teamables').on('listitems', () => {
let rows = $('#teamables .selected.listitem');
if (rows.length === teamSize) {
$('#team-name')[0].value = rows.map(row => row.data('name')).join('-');
$('#teamup').removeClass('disabled');
} else {
$('#team-name')[0].value = '';
$('#teamup').addClass('disabled');
}
});
});

View File

@@ -11,7 +11,11 @@
#set($round = $math.min($math.max($round, 1), $tour.rounds))
#end
<div class="section">
#set($parts = $api.get("tour/${params.id}/part"))
#if($tour.type == 'INDIVIDUAL' || $tour.type.startsWith('TEAM'))
#set($parts = $api.get("tour/${params.id}/part"))
#else
#set($parts = $api.get("tour/${params.id}/team"))
#end
#set($pmap = $utils.toMap($parts))
#set($roundPairing = $api.get("tour/${params.id}/pair/$round"))
#if($roundPairing.error)
@@ -46,13 +50,13 @@
<div class="players">
<div class="white player">
<div class="color">White</div>
<div class="name">$white.name $white.firstname #rank($white.rank)<br/>($white.country.toUpperCase(), $white.club)</div>
<div class="name">$white.name $!white.firstname #rank($white.rank)<br/>#if($white.country)($white.country.toUpperCase()#if($white.club), $white.club#end)#end</div>
## <div class="pin">$white.egf</div>
</div>
<div class="equal">½-½</div>
<div class="black player">
<div class="color">Black</div>
<div class="name">$black.name $black.firstname #rank($black.rank)<br/>($black.country.toUpperCase(), $black.club)</div>
<div class="name">$black.name $!black.firstname #rank($black.rank)<br/>#if($black.country)($black.country.toUpperCase()#if($black.club), $black.club#end)#end</div>
## <div class="pin">$black.egf</div>
</div>
</div>

View File

@@ -62,8 +62,8 @@
<span class="info"></span>
<select name="type">
<option value="INDIVIDUAL" #if(!$tour || $tour.type == 'INDIVIDUAL') selected #end>Individual players</option>
#* TODO
<option value="PAIRGO" #if($tour && $tour.type == 'PAIRGO') selected #end>Pair-go tournament</option>
#* TODO
<option value="RENGO2" #if($tour && $tour.type == 'RENGO2') selected #end>Rengo with 2 players teams</option>
<option value="RENGO3" #if($tour && $tour.type == 'RENGO3') selected #end>Rengo with 3 players team</option>
<option value="TEAM2" #if($tour && $tour.type == 'TEAM2') selected #end>Team of 2 individual players</option>

View File

@@ -9,6 +9,13 @@
<div class="title">Registration</div>
</div>
</div>
#if($tour.type != 'INDIVIDUAL')
<div class="step" data-step="teams">
<div class="content">
<div class="title">Teams</div>
</div>
</div>
#end
<div class="step" data-step="pairing">
<div class="content">
<div class="title">Pairing</div>

View File

@@ -27,13 +27,13 @@
<div id="pairables" class="multi-select" title="pairable players">
#foreach($p in $pairables)
#set($part = $pmap[$p])
<div data-id="$part.id" class="listitem pairable"><span class="name">$part.name $part.firstname</span><span>#rank($part.rank) $part.country</span></div>
<div data-id="$part.id" class="listitem pairable"><span class="name">$part.name#if($part.firstname) $part.firstname#end</span><span>#rank($part.rank)#if($part.country) $part.country#end</span></div>
#end
</div>
<div id="unpairables" class="multi-select" title="unpairable players">
#foreach($p in $unpairables)
#set($part = $pmap[$p])
<div data-id="$part.id" class="listitem unpairable"><span class="name">$part.name $part.firstname</span><span>#rank($part.rank) $part.country</span></div>
<div data-id="$part.id" class="listitem unpairable"><span class="name">$part.name#if($part.firstname) $part.firstname#end</span><span>#rank($part.rank)#if($part.country) $part.country#end</span></div>
#end
</div>
</div>
@@ -59,9 +59,9 @@
#set($black = $pmap[$game.b])
<div class="listitem game" data-id="$game.id">
<div class="table" data-value="$game.t">#$game.t</div>
<div class="white" data-id="$game.w">#if($white)$white.name $white.firstname#{else}BIP#end</div>
<div class="white" data-id="$game.w">#if($white)$white.name#if($white.firstname) $white.firstname#end#{else}BIP#end</div>
<div class="levels">#if($white)#rank($white.rank)#end&nbsp;/&nbsp;#if($black)#rank($black.rank)#end</div>
<div class="black" data-id="$game.b">#if($black)$black.name $black.firstname#{else}BIP#end</div>
<div class="black" data-id="$game.b">#if($black)$black.name#if($black.firstname) $black.firstname#end#{else}BIP#end</div>
<div class="handicap" data-value="$game.h">#if($game.h)h$game.h#{else}&nbsp;#end</div>
</div>
#end

View File

@@ -1,5 +1,12 @@
#set($parts = $api.get("tour/${params.id}/part"))
#set($pmap = $utils.toMap($parts))
#if($tour.type == 'INDIVIDUAL' || $tour.type.startsWith('TEAM'))
#set($pmap = $utils.toMap($parts))
#else
#set($teams = $api.get("tour/${params.id}/team"))
$log.debug("@@@@@@@@@ teams = $teams")
#set($pmap = $utils.toMap($teams))
#end
<div class="tab-content" id="registration-tab">
<div id="reg-view">
<div id="list-header">
@@ -27,11 +34,11 @@
<th>First name</th>
<th>Country</th>
<th>Club</th>
#if($tour.country == 'FR')
<th>FFG</th>
#else
##if($tour.country == 'FR')
## <th>FFG</th>
##else
<th>PIN</th>
#end
##end
<th>Rank</th>
## TableSort bug which inverts specified sort...
<th data-sort-default="1" aria-sort="ascending">Rating</th>
@@ -77,7 +84,7 @@
<i class="plus icon"></i>
Add player
</button>
#if($tour.pairing.type == 'MAC_MAHON')
#if($tour.type == 'INDIVIDUAL' && $tour.pairing.type == 'MAC_MAHON')
<button id="edit-macmahon-groups" class="ui right labeled icon floating button">
<i class="pencil icon"></i>
Mac Mahon groups
@@ -238,7 +245,7 @@
<div class="success-feedback"><i class="big green check icon"></i></div>
</div>
</div>
#if($tour.pairing.type == 'MAC_MAHON')
#if($tour.type == 'INDIVIDUAL' && $tour.pairing.type == 'MAC_MAHON')
#set($mmbase = $api.get("tour/${params.id}/standings/0"))
#if($mmbase.isObject() && ($mmbase.error || $mmbase.message))
#if($mmbase.error)

View File

@@ -30,8 +30,8 @@
#if($black && $white)
<tr id="result-$game.id" data-id="$game.id">
<td data-sort="$game.t">#$game.t</td>
<td class="white player #if($game.r == 'w' || $game.r == '#') winner #elseif($game.r == 'b' || $game.r == '0') looser #end" data-id="$white.id" data-sort="$white.name $white.firstname"><span>#if($white)$white.name $white.firstname #rank($white.rank)#{else}BIP#end</span></td>
<td class="black player #if($game.r == 'b' || $game.r == '#') winner #elseif($game.r == 'w' || $game.r == '0') looser #end" data-id="$black.id" data-sort="$black.name $black.firstname"><span>#if($black)$black.name $black.firstname #rank($black.rank)#{else}BIP#end</span></td>
<td class="white player #if($game.r == 'w' || $game.r == '#') winner #elseif($game.r == 'b' || $game.r == '0') looser #end" data-id="$white.id" data-sort="$white.name#if($white.firstname) $white.firstname#end"><span>#if($white)$white.name#if($white.firstname) $white.firstname#end #rank($white.rank)#{else}BIP#end</span></td>
<td class="black player #if($game.r == 'b' || $game.r == '#') winner #elseif($game.r == 'w' || $game.r == '0') looser #end" data-id="$black.id" data-sort="$black.name#if($black.firstname) $black.firstname#end"><span>#if($black)$black.name#if($black.firstname) $black.firstname#end #rank($black.rank)#{else}BIP#end</span></td>
<td class="result centered" data-sort="$game.r" data-result="$game.r">$dispRst[$game.r]</td>
</tr>
#end

View File

@@ -65,9 +65,9 @@
<tr>
<td>$part.num</td>
<td>$part.place</td>
<td>$part.name $part.firstname</td>
<td>$part.name#if($part.firstname) $part.firstname#end</td>
<td data-sort="$part.rank">#rank($part.rank)</td>
<td>$part.country</td>
<td>#if($part.country)$part.country#end</td>
<td>$number.format('0.#', $part.NBW)</td>
#set($mx = $round - 1)
#foreach($r in [0..$mx])

View File

@@ -0,0 +1,34 @@
#set($teamables = $utils.getTeamables($parts, $teams))
<div class="tab-content" id="teams-tab">
<div id="teams-content">
<div id="teams-lists">
<div id="teams-left">
<div id="teamables" class="multi-select" title="team members">
#foreach($part in $teamables)
<div data-id="$part.id" data-name="$part.name" class="listitem pairable"><span class="name">$part.name $part.firstname</span><span>#rank($part.rank) $part.country</span></div>
#end
</div>
</div>
<div id="teams-right">
<div id="teams-buttons">
<div class="vert flex">
<input type="text" id="team-name" placeholder="team name"/>
<button id="teamup" class="ui blue right labeled icon floating disabled button">
<i class="angle double right icon"></i>
Team up
</button>
</div>
<button id="split" class="ui orange right labeled icon floating button">
<i class="angle double left icon"></i>
Split
</button>
</div>
<div id="teams" class="multi-select" title="teams">
#foreach($team in $teams)
<div data-id="$team.id" class="listitem team"><span class="name">$team.name</span><span>#rank($team.rank)#if($team.country) $team.country#end</span></div>
#end
</div>
</div>
</div>
</div>
</div>

View File

@@ -38,6 +38,9 @@
#translate('tour-information.inc.html')
#if($tour)
#translate('tour-registration.inc.html')
#if($tour.type != 'INDIVIDUAL')
#translate('tour-teams.inc.html')
#end
#translate('tour-pairing.inc.html')
#translate('tour-results.inc.html')
#translate('tour-standings.inc.html')
@@ -54,7 +57,7 @@
let correction = #if($tour.pairing.type == 'MAC_MAHON')${tour.pairing.handicap.correction}#{else}0#end;
let standingsUpToDate = true;
let pairablesUpToDate = true;
// $params
const teamSize = $tour.teamSize;
#end
#set($datepickerLocale = $translate.datepickerLocale($request.lang, $request.loc))
const datepickerLocale = '$datepickerLocale';
@@ -162,6 +165,9 @@
#include('/js/tour-information.inc.js')
#if($tour)
#include('/js/tour-registration.inc.js')
#if($tour.type != 'INDIVIDUAL')
#include('/js/tour-teams.inc.js')
#end
#include('/js/tour-pairing.inc.js')
#include('/js/tour-results.inc.js')
#include('/js/tour-standings.inc.js')