]> git.localhorst.tv Git - alttp.git/commitdiff
switch participant list to scoreboard
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Tue, 15 Mar 2022 19:43:24 +0000 (20:43 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Tue, 15 Mar 2022 19:43:24 +0000 (20:43 +0100)
package-lock.json
package.json
resources/js/components/tournament/Detail.js
resources/js/components/tournament/Scoreboard.js [new file with mode: 0644]
resources/js/helpers/Tournament.js
resources/js/i18n/de.js

index 42f84ade7ae486f00f6fe0fa93a37a0e54dc982e..398293aab23c1d38ec0a40ed9f8fd1baf811981e 100644 (file)
             "dependencies": {
                 "anymatch": "~3.1.2",
                 "braces": "~3.0.2",
+                "fsevents": "~2.3.2",
                 "glob-parent": "~5.1.2",
                 "is-binary-path": "~2.1.0",
                 "is-glob": "~4.0.1",
             "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==",
             "dev": true,
             "dependencies": {
+                "colors": "1.4.0",
                 "string-width": "^4.2.0"
             },
             "engines": {
             "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
             "dev": true,
             "dependencies": {
+                "graceful-fs": "^4.1.6",
                 "universalify": "^2.0.0"
             },
             "optionalDependencies": {
index abdb0d544d183ef4cbb89db733cb3411716c1ddc..b03f12df6d8569332e115044c2aed1bb23aa8a1a 100644 (file)
@@ -12,7 +12,7 @@
     "eslintConfig": {
         "env": {
             "browser": true,
-                       "node": true
+            "node": true
         },
         "extends": [
             "eslint:recommended",
@@ -24,7 +24,7 @@
             "sourceType": "module"
         },
         "rules": {
-                       "import/no-named-as-default-member": 0,
+            "import/no-named-as-default-member": 0,
             "max-len": [
                 "warn",
                 {
index 912d2a26d58df7a0aedcdfd87a3249353bc1b949..1dae1b31ba52d720fe2e59c72ce594bdbbece960 100644 (file)
@@ -3,7 +3,7 @@ import React from 'react';
 import { Button, Container } from 'react-bootstrap';
 import { withTranslation } from 'react-i18next';
 
-import Participants from '../participants/List';
+import Scoreboard from './Scoreboard';
 import Protocol from '../protocol/Protocol';
 import Rounds from '../rounds/List';
 import {
@@ -25,10 +25,10 @@ const Detail = ({
                : null}
        </div>
        <div className="d-flex align-items-center justify-content-between">
-               <h2>{i18n.t('participants.heading')}</h2>
+               <h2>{i18n.t('tournaments.scoreboard')}</h2>
        </div>
        {tournament.participants ?
-               <Participants participants={tournament.participants} tournament={tournament} />
+               <Scoreboard tournament={tournament} />
        : null}
        <div className="d-flex align-items-center justify-content-between">
                <h2>{i18n.t('rounds.heading')}</h2>
diff --git a/resources/js/components/tournament/Scoreboard.js b/resources/js/components/tournament/Scoreboard.js
new file mode 100644 (file)
index 0000000..008974b
--- /dev/null
@@ -0,0 +1,33 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Table } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import Box from '../users/Box';
+import { calculateScores } from '../../helpers/Tournament';
+import i18n from '../../i18n';
+
+const Scoreboard = ({ tournament }) =>
+<Table striped className="scoreboard">
+       <thead>
+               <tr>
+                       <th>{i18n.t('participants.participant')}</th>
+                       <th className="text-end">{i18n.t('participants.score')}</th>
+               </tr>
+       </thead>
+       <tbody>
+       {calculateScores(tournament).map(score =>
+               <tr className="score" key={score.participant.id}>
+                       <td><Box user={score.participant.user} /></td>
+                       <td className="text-end text-lg">{score.score}</td>
+               </tr>
+       )}
+       </tbody>
+</Table>;
+
+Scoreboard.propTypes = {
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default withTranslation()(Scoreboard);
index 6b4ca28fb93c2c185ec096ed4579707a93f52ead..2c145a83cc5aa48bf6e3b0c4688ae9c4e5967aa4 100644 (file)
@@ -1,6 +1,47 @@
 import Participant from './Participant';
 import Round from './Round';
 
+export const calculateScores = tournament => {
+       if (!tournament || !tournament.participants || !tournament.participants.length) return [];
+       const scores = tournament.participants.map(participant => ({ participant, score: 0 }));
+       if (!tournament.rounds || !tournament.rounds.length) return scores;
+       tournament.rounds.forEach(round => {
+               const filtered = Participant
+                       .sortByResult(tournament.participants, round)
+                       .map(p => ({ participant: p, result: Participant.findResult(p, round) }))
+                       .filter(r => r.result && (r.result.time || r.result.forfeit))
+                       .reverse();
+               let running = 0;
+               let bonus = 1;
+               let lastResult = null;
+               for (let i = 0; i < filtered.length; ++i) {
+                       const score = scores.find(s => s.participant.id === filtered[i].participant.id);
+                       if (!score) return;
+                       const result = filtered[i].result;
+                       const betterThanLast = lastResult === null || result.time < lastResult;
+                       if (!result.forfeit && betterThanLast) {
+                               running += bonus;
+                               lastResult = result.time;
+                               bonus = 1;
+                       } else {
+                               ++bonus;
+                       }
+                       if (!result.forfeit) {
+                               score.score += running;
+                       }
+               }
+       });
+       return scores.sort(compareScore).reverse();
+};
+
+export const compareScore = (a, b) => {
+       const a_score = a && a.score ? a.score : 0;
+       const b_score = b && b.score ? b.score : 0;
+       if (a_score < b_score) return -1;
+       if (b_score < a_score) return 1;
+       return 0;
+};
+
 export const findParticipant = (tournament, user) => {
        if (!tournament || !tournament.participants || !tournament.participants.length) return null;
        if (!user || !user.id) return null;
@@ -38,6 +79,8 @@ export const sortParticipants = tournament => {
 };
 
 export default {
+       calculateScores,
+       compareScore,
        findParticipant,
        patchResult,
        sortParticipants,
index de250899a24930f67e9088f382b12b851bcd50ff..97089e6013fe89a6dc450cb73f6db1aad669a57d 100644 (file)
@@ -32,6 +32,8 @@ export default {
                participants: {
                        empty: 'Noch keine Teilnehmer eingetragen',
                        heading: 'Teilnehmer',
+                       participant: 'Teilnehmer',
+                       score: 'Punktzahl',
                },
                protocol: {
                        description: {
@@ -65,6 +67,9 @@ export default {
                        seed: 'Seed',
                        setSeed: 'Seed eintragen',
                },
+               tournaments: {
+                       scoreboard: 'Scoreboard',
+               },
                validation: {
                        error: {
                                required: 'Bitte ausfüllen',