]> git.localhorst.tv Git - alttp.git/commitdiff
basic score chart
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Tue, 12 Apr 2022 18:49:22 +0000 (20:49 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Tue, 12 Apr 2022 18:49:22 +0000 (20:49 +0200)
package-lock.json
package.json
resources/js/components/common/Icon.js
resources/js/components/tournament/Detail.js
resources/js/components/tournament/ScoreChart.js [new file with mode: 0644]
resources/js/components/tournament/ScoreChartButton.js [new file with mode: 0644]
resources/js/components/tournament/ScoreChartDialog.js [new file with mode: 0644]
resources/js/helpers/Participant.js
resources/js/helpers/Tournament.js
resources/js/i18n/de.js
resources/js/i18n/en.js

index 398293aab23c1d38ec0a40ed9f8fd1baf811981e..0ae79c206e83eb61a8ce421e7399f822561af4d3 100644 (file)
@@ -22,6 +22,7 @@
                 "react-i18next": "^11.15.6",
                 "react-router-bootstrap": "^0.26.0",
                 "react-router-dom": "^6.2.2",
+                "recharts": "^2.1.9",
                 "toastr": "^2.1.4",
                 "yup": "^0.32.11"
             },
                 "@types/node": "*"
             }
         },
+        "node_modules/@types/d3-color": {
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-2.0.3.tgz",
+            "integrity": "sha512-+0EtEjBfKEDtH9Rk3u3kLOUXM5F+iZK+WvASPb0MhIZl8J8NUvGeZRwKCXl+P3HkYx5TdU4YtcibpqHkSR9n7w=="
+        },
+        "node_modules/@types/d3-interpolate": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-2.0.2.tgz",
+            "integrity": "sha512-lElyqlUfIPyWG/cD475vl6msPL4aMU7eJvx1//Q177L8mdXoVPFl1djIESF2FKnc0NyaHvQlJpWwKJYwAhUoCw==",
+            "dependencies": {
+                "@types/d3-color": "^2"
+            }
+        },
+        "node_modules/@types/d3-path": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-2.0.2.tgz",
+            "integrity": "sha512-3YHpvDw9LzONaJzejXLOwZ3LqwwkoXb9LI2YN7Hbd6pkGo5nIlJ09ul4bQhBN4hQZJKmUpX8HkVqbzgUKY48cg=="
+        },
+        "node_modules/@types/d3-scale": {
+            "version": "3.3.2",
+            "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-3.3.2.tgz",
+            "integrity": "sha512-gGqr7x1ost9px3FvIfUMi5XA/F/yAf4UkUDtdQhpH92XCT0Oa7zkkRzY61gPVJq+DxpHn/btouw5ohWkbBsCzQ==",
+            "dependencies": {
+                "@types/d3-time": "^2"
+            }
+        },
+        "node_modules/@types/d3-shape": {
+            "version": "2.1.3",
+            "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-2.1.3.tgz",
+            "integrity": "sha512-HAhCel3wP93kh4/rq+7atLdybcESZ5bRHDEZUojClyZWsRuEMo3A52NGYJSh48SxfxEU6RZIVbZL2YFZ2OAlzQ==",
+            "dependencies": {
+                "@types/d3-path": "^2"
+            }
+        },
+        "node_modules/@types/d3-time": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-2.1.1.tgz",
+            "integrity": "sha512-9MVYlmIgmRR31C5b4FVSWtuMmBHh2mOWQYfl7XAYOa8dsnb7iEmUmRSWSFgXFtkjxO65d7hTUHQC+RhR/9IWFg=="
+        },
         "node_modules/@types/eslint": {
             "version": "8.4.1",
             "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz",
                 "@types/react": "*"
             }
         },
+        "node_modules/@types/resize-observer-browser": {
+            "version": "0.1.7",
+            "resolved": "https://registry.npmjs.org/@types/resize-observer-browser/-/resize-observer-browser-0.1.7.tgz",
+            "integrity": "sha512-G9eN0Sn0ii9PWQ3Vl72jDPgeJwRWhv2Qk/nQkJuWmRmOB4HX3/BhD5SE1dZs/hzPZL/WKnvF0RHdTSG54QJFyg=="
+        },
         "node_modules/@types/retry": {
             "version": "0.12.1",
             "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz",
                 "node": ">=0.10.0"
             }
         },
+        "node_modules/css-unit-converter": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
+            "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
+        },
         "node_modules/css-what": {
             "version": "5.1.0",
             "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz",
             "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz",
             "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw=="
         },
+        "node_modules/d3-array": {
+            "version": "2.12.1",
+            "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
+            "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==",
+            "dependencies": {
+                "internmap": "^1.0.0"
+            }
+        },
+        "node_modules/d3-color": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz",
+            "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ=="
+        },
+        "node_modules/d3-format": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz",
+            "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA=="
+        },
+        "node_modules/d3-interpolate": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz",
+            "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==",
+            "dependencies": {
+                "d3-color": "1 - 2"
+            }
+        },
+        "node_modules/d3-path": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz",
+            "integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA=="
+        },
+        "node_modules/d3-scale": {
+            "version": "3.3.0",
+            "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz",
+            "integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==",
+            "dependencies": {
+                "d3-array": "^2.3.0",
+                "d3-format": "1 - 2",
+                "d3-interpolate": "1.2.0 - 2",
+                "d3-time": "^2.1.1",
+                "d3-time-format": "2 - 3"
+            }
+        },
+        "node_modules/d3-shape": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-2.1.0.tgz",
+            "integrity": "sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA==",
+            "dependencies": {
+                "d3-path": "1 - 2"
+            }
+        },
+        "node_modules/d3-time": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz",
+            "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==",
+            "dependencies": {
+                "d3-array": "2"
+            }
+        },
+        "node_modules/d3-time-format": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz",
+            "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==",
+            "dependencies": {
+                "d3-time": "1 - 2"
+            }
+        },
         "node_modules/debug": {
             "version": "4.3.3",
             "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
                 }
             }
         },
+        "node_modules/decimal.js-light": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
+            "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="
+        },
         "node_modules/deep-equal": {
             "version": "1.1.1",
             "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
         "node_modules/eventemitter3": {
             "version": "4.0.7",
             "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
-            "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
-            "dev": true
+            "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
         },
         "node_modules/events": {
             "version": "3.3.0",
             "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
             "dev": true
         },
+        "node_modules/fast-equals": {
+            "version": "2.0.4",
+            "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-2.0.4.tgz",
+            "integrity": "sha512-caj/ZmjHljPrZtbzJ3kfH5ia/k4mTJe/qSiXAGzxZWRZgsgDV0cvNaQULqUX8t0/JVlzzEdYOwCN5DmzTxoD4w=="
+        },
         "node_modules/fast-glob": {
             "version": "3.2.11",
             "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
                 "node": ">= 0.4"
             }
         },
+        "node_modules/internmap": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
+            "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="
+        },
         "node_modules/interpret": {
             "version": "2.2.0",
             "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
                 "node": ">=0.12"
             }
         },
+        "node_modules/performance-now": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+            "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+        },
         "node_modules/picocolors": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
+        "node_modules/raf": {
+            "version": "3.4.1",
+            "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
+            "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
+            "dependencies": {
+                "performance-now": "^2.1.0"
+            }
+        },
         "node_modules/randombytes": {
             "version": "2.1.0",
             "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
             "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
             "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
         },
+        "node_modules/react-resize-detector": {
+            "version": "6.7.8",
+            "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-6.7.8.tgz",
+            "integrity": "sha512-0FaEcUBAbn+pq3PT5a9hHRebUfuS1SRLGLpIw8LydU7zX429I6XJgKerKAMPsJH0qWAl6o5bVKNqFJqr6tGPYw==",
+            "dependencies": {
+                "@types/resize-observer-browser": "^0.1.6",
+                "lodash": "^4.17.21",
+                "resize-observer-polyfill": "^1.5.1"
+            },
+            "peerDependencies": {
+                "react": "^16.0.0 || ^17.0.0",
+                "react-dom": "^16.0.0 || ^17.0.0"
+            }
+        },
         "node_modules/react-router": {
             "version": "6.2.2",
             "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.2.tgz",
                 "react-dom": ">=16.8"
             }
         },
+        "node_modules/react-smooth": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.0.tgz",
+            "integrity": "sha512-wK4dBBR6P21otowgMT9toZk+GngMplGS1O5gk+2WSiHEXIrQgDvhR5IIlT74Vtu//qpTcipkgo21dD7a7AUNxw==",
+            "dependencies": {
+                "fast-equals": "^2.0.0",
+                "raf": "^3.4.0",
+                "react-transition-group": "2.9.0"
+            },
+            "peerDependencies": {
+                "prop-types": "^15.6.0",
+                "react": "^15.0.0 || ^16.0.0 || ^17.0.0",
+                "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0"
+            }
+        },
+        "node_modules/react-smooth/node_modules/dom-helpers": {
+            "version": "3.4.0",
+            "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
+            "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
+            "dependencies": {
+                "@babel/runtime": "^7.1.2"
+            }
+        },
+        "node_modules/react-smooth/node_modules/react-transition-group": {
+            "version": "2.9.0",
+            "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz",
+            "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==",
+            "dependencies": {
+                "dom-helpers": "^3.4.0",
+                "loose-envify": "^1.4.0",
+                "prop-types": "^15.6.2",
+                "react-lifecycles-compat": "^3.0.4"
+            },
+            "peerDependencies": {
+                "react": ">=15.0.0",
+                "react-dom": ">=15.0.0"
+            }
+        },
         "node_modules/react-transition-group": {
             "version": "4.4.2",
             "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz",
                 "node": ">=8.10.0"
             }
         },
+        "node_modules/recharts": {
+            "version": "2.1.9",
+            "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.1.9.tgz",
+            "integrity": "sha512-VozH5uznUvGqD7n224FGj7cmMAenlS0HPCs+7r2HeeHiQK6un6z0CTZfWVAB860xbcr4m+BN/EGMPZmYWd34Rg==",
+            "dependencies": {
+                "@types/d3-interpolate": "^2.0.0",
+                "@types/d3-scale": "^3.0.0",
+                "@types/d3-shape": "^2.0.0",
+                "classnames": "^2.2.5",
+                "d3-interpolate": "^2.0.0",
+                "d3-scale": "^3.0.0",
+                "d3-shape": "^2.0.0",
+                "eventemitter3": "^4.0.1",
+                "lodash": "^4.17.19",
+                "react-is": "^16.10.2",
+                "react-resize-detector": "^6.6.3",
+                "react-smooth": "^2.0.0",
+                "recharts-scale": "^0.4.4",
+                "reduce-css-calc": "^2.1.8"
+            },
+            "engines": {
+                "node": ">=12"
+            },
+            "peerDependencies": {
+                "react": "^16.0.0 || ^17.0.0",
+                "react-dom": "^16.0.0 || ^17.0.0"
+            }
+        },
+        "node_modules/recharts-scale": {
+            "version": "0.4.5",
+            "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz",
+            "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==",
+            "dependencies": {
+                "decimal.js-light": "^2.4.1"
+            }
+        },
         "node_modules/rechoir": {
             "version": "0.7.1",
             "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz",
                 "node": ">= 0.10"
             }
         },
+        "node_modules/reduce-css-calc": {
+            "version": "2.1.8",
+            "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz",
+            "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==",
+            "dependencies": {
+                "css-unit-converter": "^1.1.1",
+                "postcss-value-parser": "^3.3.0"
+            }
+        },
+        "node_modules/reduce-css-calc/node_modules/postcss-value-parser": {
+            "version": "3.3.1",
+            "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+            "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
+        },
         "node_modules/regenerate": {
             "version": "1.4.2",
             "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
             "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
             "dev": true
         },
+        "node_modules/resize-observer-polyfill": {
+            "version": "1.5.1",
+            "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
+            "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
+        },
         "node_modules/resolve": {
             "version": "1.22.0",
             "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
                 "@types/node": "*"
             }
         },
+        "@types/d3-color": {
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-2.0.3.tgz",
+            "integrity": "sha512-+0EtEjBfKEDtH9Rk3u3kLOUXM5F+iZK+WvASPb0MhIZl8J8NUvGeZRwKCXl+P3HkYx5TdU4YtcibpqHkSR9n7w=="
+        },
+        "@types/d3-interpolate": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-2.0.2.tgz",
+            "integrity": "sha512-lElyqlUfIPyWG/cD475vl6msPL4aMU7eJvx1//Q177L8mdXoVPFl1djIESF2FKnc0NyaHvQlJpWwKJYwAhUoCw==",
+            "requires": {
+                "@types/d3-color": "^2"
+            }
+        },
+        "@types/d3-path": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-2.0.2.tgz",
+            "integrity": "sha512-3YHpvDw9LzONaJzejXLOwZ3LqwwkoXb9LI2YN7Hbd6pkGo5nIlJ09ul4bQhBN4hQZJKmUpX8HkVqbzgUKY48cg=="
+        },
+        "@types/d3-scale": {
+            "version": "3.3.2",
+            "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-3.3.2.tgz",
+            "integrity": "sha512-gGqr7x1ost9px3FvIfUMi5XA/F/yAf4UkUDtdQhpH92XCT0Oa7zkkRzY61gPVJq+DxpHn/btouw5ohWkbBsCzQ==",
+            "requires": {
+                "@types/d3-time": "^2"
+            }
+        },
+        "@types/d3-shape": {
+            "version": "2.1.3",
+            "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-2.1.3.tgz",
+            "integrity": "sha512-HAhCel3wP93kh4/rq+7atLdybcESZ5bRHDEZUojClyZWsRuEMo3A52NGYJSh48SxfxEU6RZIVbZL2YFZ2OAlzQ==",
+            "requires": {
+                "@types/d3-path": "^2"
+            }
+        },
+        "@types/d3-time": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-2.1.1.tgz",
+            "integrity": "sha512-9MVYlmIgmRR31C5b4FVSWtuMmBHh2mOWQYfl7XAYOa8dsnb7iEmUmRSWSFgXFtkjxO65d7hTUHQC+RhR/9IWFg=="
+        },
         "@types/eslint": {
             "version": "8.4.1",
             "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz",
                 "@types/react": "*"
             }
         },
+        "@types/resize-observer-browser": {
+            "version": "0.1.7",
+            "resolved": "https://registry.npmjs.org/@types/resize-observer-browser/-/resize-observer-browser-0.1.7.tgz",
+            "integrity": "sha512-G9eN0Sn0ii9PWQ3Vl72jDPgeJwRWhv2Qk/nQkJuWmRmOB4HX3/BhD5SE1dZs/hzPZL/WKnvF0RHdTSG54QJFyg=="
+        },
         "@types/retry": {
             "version": "0.12.1",
             "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz",
                 }
             }
         },
+        "css-unit-converter": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
+            "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
+        },
         "css-what": {
             "version": "5.1.0",
             "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz",
             "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz",
             "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw=="
         },
+        "d3-array": {
+            "version": "2.12.1",
+            "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
+            "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==",
+            "requires": {
+                "internmap": "^1.0.0"
+            }
+        },
+        "d3-color": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz",
+            "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ=="
+        },
+        "d3-format": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz",
+            "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA=="
+        },
+        "d3-interpolate": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz",
+            "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==",
+            "requires": {
+                "d3-color": "1 - 2"
+            }
+        },
+        "d3-path": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz",
+            "integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA=="
+        },
+        "d3-scale": {
+            "version": "3.3.0",
+            "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz",
+            "integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==",
+            "requires": {
+                "d3-array": "^2.3.0",
+                "d3-format": "1 - 2",
+                "d3-interpolate": "1.2.0 - 2",
+                "d3-time": "^2.1.1",
+                "d3-time-format": "2 - 3"
+            }
+        },
+        "d3-shape": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-2.1.0.tgz",
+            "integrity": "sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA==",
+            "requires": {
+                "d3-path": "1 - 2"
+            }
+        },
+        "d3-time": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz",
+            "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==",
+            "requires": {
+                "d3-array": "2"
+            }
+        },
+        "d3-time-format": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz",
+            "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==",
+            "requires": {
+                "d3-time": "1 - 2"
+            }
+        },
         "debug": {
             "version": "4.3.3",
             "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
                 "ms": "2.1.2"
             }
         },
+        "decimal.js-light": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
+            "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="
+        },
         "deep-equal": {
             "version": "1.1.1",
             "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
         "eventemitter3": {
             "version": "4.0.7",
             "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
-            "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
-            "dev": true
+            "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
         },
         "events": {
             "version": "3.3.0",
             "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
             "dev": true
         },
+        "fast-equals": {
+            "version": "2.0.4",
+            "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-2.0.4.tgz",
+            "integrity": "sha512-caj/ZmjHljPrZtbzJ3kfH5ia/k4mTJe/qSiXAGzxZWRZgsgDV0cvNaQULqUX8t0/JVlzzEdYOwCN5DmzTxoD4w=="
+        },
         "fast-glob": {
             "version": "3.2.11",
             "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
                 "side-channel": "^1.0.4"
             }
         },
+        "internmap": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
+            "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="
+        },
         "interpret": {
             "version": "2.2.0",
             "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
                 "sha.js": "^2.4.8"
             }
         },
+        "performance-now": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+            "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+        },
         "picocolors": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
             "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
             "dev": true
         },
+        "raf": {
+            "version": "3.4.1",
+            "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
+            "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
+            "requires": {
+                "performance-now": "^2.1.0"
+            }
+        },
         "randombytes": {
             "version": "2.1.0",
             "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
             "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
             "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
         },
+        "react-resize-detector": {
+            "version": "6.7.8",
+            "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-6.7.8.tgz",
+            "integrity": "sha512-0FaEcUBAbn+pq3PT5a9hHRebUfuS1SRLGLpIw8LydU7zX429I6XJgKerKAMPsJH0qWAl6o5bVKNqFJqr6tGPYw==",
+            "requires": {
+                "@types/resize-observer-browser": "^0.1.6",
+                "lodash": "^4.17.21",
+                "resize-observer-polyfill": "^1.5.1"
+            }
+        },
         "react-router": {
             "version": "6.2.2",
             "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.2.tgz",
                 "react-router": "6.2.2"
             }
         },
+        "react-smooth": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.0.tgz",
+            "integrity": "sha512-wK4dBBR6P21otowgMT9toZk+GngMplGS1O5gk+2WSiHEXIrQgDvhR5IIlT74Vtu//qpTcipkgo21dD7a7AUNxw==",
+            "requires": {
+                "fast-equals": "^2.0.0",
+                "raf": "^3.4.0",
+                "react-transition-group": "2.9.0"
+            },
+            "dependencies": {
+                "dom-helpers": {
+                    "version": "3.4.0",
+                    "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
+                    "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
+                    "requires": {
+                        "@babel/runtime": "^7.1.2"
+                    }
+                },
+                "react-transition-group": {
+                    "version": "2.9.0",
+                    "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz",
+                    "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==",
+                    "requires": {
+                        "dom-helpers": "^3.4.0",
+                        "loose-envify": "^1.4.0",
+                        "prop-types": "^15.6.2",
+                        "react-lifecycles-compat": "^3.0.4"
+                    }
+                }
+            }
+        },
         "react-transition-group": {
             "version": "4.4.2",
             "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz",
                 "picomatch": "^2.2.1"
             }
         },
+        "recharts": {
+            "version": "2.1.9",
+            "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.1.9.tgz",
+            "integrity": "sha512-VozH5uznUvGqD7n224FGj7cmMAenlS0HPCs+7r2HeeHiQK6un6z0CTZfWVAB860xbcr4m+BN/EGMPZmYWd34Rg==",
+            "requires": {
+                "@types/d3-interpolate": "^2.0.0",
+                "@types/d3-scale": "^3.0.0",
+                "@types/d3-shape": "^2.0.0",
+                "classnames": "^2.2.5",
+                "d3-interpolate": "^2.0.0",
+                "d3-scale": "^3.0.0",
+                "d3-shape": "^2.0.0",
+                "eventemitter3": "^4.0.1",
+                "lodash": "^4.17.19",
+                "react-is": "^16.10.2",
+                "react-resize-detector": "^6.6.3",
+                "react-smooth": "^2.0.0",
+                "recharts-scale": "^0.4.4",
+                "reduce-css-calc": "^2.1.8"
+            }
+        },
+        "recharts-scale": {
+            "version": "0.4.5",
+            "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz",
+            "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==",
+            "requires": {
+                "decimal.js-light": "^2.4.1"
+            }
+        },
         "rechoir": {
             "version": "0.7.1",
             "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz",
                 "resolve": "^1.9.0"
             }
         },
+        "reduce-css-calc": {
+            "version": "2.1.8",
+            "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz",
+            "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==",
+            "requires": {
+                "css-unit-converter": "^1.1.1",
+                "postcss-value-parser": "^3.3.0"
+            },
+            "dependencies": {
+                "postcss-value-parser": {
+                    "version": "3.3.1",
+                    "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+                    "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
+                }
+            }
+        },
         "regenerate": {
             "version": "1.4.2",
             "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
             "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
             "dev": true
         },
+        "resize-observer-polyfill": {
+            "version": "1.5.1",
+            "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
+            "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
+        },
         "resolve": {
             "version": "1.22.0",
             "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
index b03f12df6d8569332e115044c2aed1bb23aa8a1a..2732cb74166ec33085c5d0d5d3e9d877ab03060e 100644 (file)
@@ -87,6 +87,7 @@
         "react-i18next": "^11.15.6",
         "react-router-bootstrap": "^0.26.0",
         "react-router-dom": "^6.2.2",
+        "recharts": "^2.1.9",
         "toastr": "^2.1.4",
         "yup": "^0.32.11"
     }
index 6d050902d584cbd55293fa8b7859b72f95df580f..c0c68176950b5c7d1a68f0a65c6a05f0b628ce88 100644 (file)
@@ -61,6 +61,7 @@ Icon.ACCEPT = makePreset('AcceptIcon', 'square-check');
 Icon.ADD = makePreset('AddIcon', 'circle-plus');
 Icon.APPLY = makePreset('ApplyIcon', 'right-to-bracket');
 Icon.APPLICATIONS = makePreset('ApplicationsIcon', 'person-running');
+Icon.CHART = makePreset('ChartIcon', 'chart-line');
 Icon.DISCORD = makePreset('DiscordIcon', ['fab', 'discord']);
 Icon.EDIT = makePreset('EditIcon', 'edit');
 Icon.FINISHED = makePreset('FinishedIcon', 'square-check');
index cdc9b601bd3b3c81448b1e3015e57b312f3922bc..d4e23cdba4e0ca359a634d2fda2b73e896e595c1 100644 (file)
@@ -5,6 +5,7 @@ import { withTranslation } from 'react-i18next';
 
 import ApplyButton from './ApplyButton';
 import Scoreboard from './Scoreboard';
+import ScoreChartButton from './ScoreChartButton';
 import ApplicationsButton from '../applications/Button';
 import Protocol from '../protocol/Protocol';
 import Rounds from '../rounds/List';
@@ -61,6 +62,9 @@ const Detail = ({
                        <div className="tournament-sidebar">
                                <div className="d-flex align-items-center justify-content-between">
                                        <h2>{i18n.t('tournaments.scoreboard')}</h2>
+                                       {hasRunners(tournament) && tournament.rounds.length > 2 ?
+                                               <ScoreChartButton tournament={tournament} />
+                                       : null}
                                </div>
                                {hasRunners(tournament) ?
                                        <Scoreboard tournament={tournament} />
diff --git a/resources/js/components/tournament/ScoreChart.js b/resources/js/components/tournament/ScoreChart.js
new file mode 100644 (file)
index 0000000..b63c81e
--- /dev/null
@@ -0,0 +1,46 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Legend, Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';
+
+import { getUserName } from '../../helpers/Participant';
+import { getRunners, getScoreTable } from '../../helpers/Tournament';
+
+const COLORS = [
+       '#7cb5ec',
+       '#434348',
+       '#90ed7d',
+       '#f7a35c',
+       '#8085e9',
+       '#f15c80',
+       '#e4d354',
+       '#2b908f',
+       '#f45b5b',
+       '#91e8e1',
+];
+
+const ScoreChart = ({
+       tournament,
+}) =>
+<ResponsiveContainer height="100%" width="100%">
+       <LineChart data={getScoreTable(tournament)} height={720} width={1280}>
+               <XAxis dataKey="number" />
+               <YAxis />
+               <Tooltip />
+               <Legend />
+               {getRunners(tournament).map((runner, index) =>
+                       <Line
+                               dataKey={getUserName(runner)}
+                               key={runner.id}
+                               stroke={COLORS[index % COLORS.length]}
+                               type="monotone"
+                       />
+               )}
+       </LineChart>
+</ResponsiveContainer>;
+
+ScoreChart.propTypes = {
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default ScoreChart;
diff --git a/resources/js/components/tournament/ScoreChartButton.js b/resources/js/components/tournament/ScoreChartButton.js
new file mode 100644 (file)
index 0000000..9074487
--- /dev/null
@@ -0,0 +1,34 @@
+import PropTypes from 'prop-types';
+import React, { useState } from 'react';
+import { Button } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import ScoreChartDialog from './ScoreChartDialog';
+import Icon from '../common/Icon';
+import i18n from '../../i18n';
+
+const ScoreChartButton = ({ tournament }) => {
+       const [showDialog, setShowDialog] = useState(false);
+
+       return <>
+               <Button
+                       onClick={() => setShowDialog(true)}
+                       title={i18n.t('button.chart')}
+                       variant="info"
+               >
+                       <Icon.CHART title="" />
+               </Button>
+               <ScoreChartDialog
+                       onHide={() => setShowDialog(false)}
+                       tournament={tournament}
+                       show={showDialog}
+               />
+       </>;
+};
+
+ScoreChartButton.propTypes = {
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default withTranslation()(ScoreChartButton);
diff --git a/resources/js/components/tournament/ScoreChartDialog.js b/resources/js/components/tournament/ScoreChartDialog.js
new file mode 100644 (file)
index 0000000..84e3873
--- /dev/null
@@ -0,0 +1,37 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Modal } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import ScoreChart from './ScoreChart';
+import i18n from '../../i18n';
+
+const ScoreChartDialog = ({
+       onHide,
+       show,
+       tournament,
+}) =>
+<Modal className="score-chart-dialog" onHide={onHide} show={show} size="lg">
+       <Modal.Header closeButton>
+               <Modal.Title>
+                       {i18n.t('tournaments.scoreChart')}
+               </Modal.Title>
+       </Modal.Header>
+       <Modal.Body style={{ height: '80vh' }}>
+               <ScoreChart tournament={tournament} />
+       </Modal.Body>
+       <Modal.Footer>
+               <Button onClick={onHide} variant="secondary">
+                       {i18n.t('button.close')}
+               </Button>
+       </Modal.Footer>
+</Modal>;
+
+ScoreChartDialog.propTypes = {
+       onHide: PropTypes.func,
+       show: PropTypes.bool,
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default withTranslation()(ScoreChartDialog);
index d7bdd7c4a41055a8f7d067c2f44c1f02ffc1a5b2..7d649526924a35c0812938a07b85aa4bd978f901 100644 (file)
@@ -43,8 +43,8 @@ export const compareResult = round => (a, b) => {
 };
 
 export const compareUsername = (a, b) => {
-       const a_name = a && a.user ? User.getUserName(a.user) : '';
-       const b_name = b && b.user ? User.getUserName(b.user) : '';
+       const a_name = getUserName(a);
+       const b_name = getUserName(b);
        return a_name.localeCompare(b_name);
 };
 
@@ -54,6 +54,9 @@ export const findResult = (participant, round) => {
        return round.results.find(result => result.user_id === participant.user_id);
 };
 
+export const getUserName = participant =>
+       participant.user ? User.getUserName(participant.user) : '';
+
 export const isRunner = participant =>
        participant && participant.roles && participant.roles.includes('runner');
 
@@ -101,6 +104,7 @@ export default {
        compareResult,
        compareUsername,
        findResult,
+       getUserName,
        isRunner,
        isTournamentAdmin,
        isTournamentCrew,
index 60354c2b6bdeae9d927a0cd32714b74e6941d830..7ff04df0d821da7874e58a56f2337bc69c8d12ea 100644 (file)
@@ -30,6 +30,28 @@ export const getRunners = tournament => {
                .sort(Participant.compareUsername);
 };
 
+export const getScoreTable = tournament => {
+       if (!tournament || !tournament.rounds || !tournament.rounds.length) return [];
+       const runners = getRunners(tournament);
+       if (!runners.length) return [];
+       const running = {};
+       runners.forEach(participant => {
+               running[participant.id] = 0;
+       });
+       const data = tournament.rounds.reverse().map(round => {
+               const entry = { number: `#${round.number}` };
+               runners.forEach(participant => {
+                       const result = Participant.findResult(participant, round);
+                       if (result && result.score) {
+                               running[participant.id] += result.score;
+                               entry[Participant.getUserName(participant)] = running[participant.id];
+                       }
+               });
+               return entry;
+       });
+       return data;
+};
+
 export const getTournamentAdmins = tournament => {
        if (!tournament || !tournament.participants || !tournament.participants.length) return [];
        return tournament.participants
index 92c64f67305c094fc83861f0db564ee030d58bb1..096a62977c016c3ddcf526ab766da181c7a322a3 100644 (file)
@@ -13,6 +13,7 @@ export default {
                        add: 'Hinzufügen',
                        back: 'Zurück',
                        cancel: 'Abbrechen',
+                       chart: 'Diagramm',
                        close: 'Schließen',
                        edit: 'Bearbeiten',
                        help: 'Hilfe',
@@ -43,7 +44,9 @@ export default {
                },
                icon: {
                        AddIcon: 'Hinzufügen',
+                       ApplicationsIcon: 'Anträge',
                        ApplyIcon: 'Beantragen',
+                       ChartIcon: 'Diagramm',
                        DiscordIcon: 'Discord',
                        EditIcon: 'Bearbeiten',
                        FinishedIcon: 'Abgeschlossen',
@@ -212,6 +215,7 @@ export default {
                        noApplications: 'Derzeit keine Anmeldungen',
                        noRecord: 'Turnier wird nicht gewertet',
                        scoreboard: 'Scoreboard',
+                       scoreChart: 'Turnierverlauf',
                },
                users: {
                        discordTag: 'Discord Tag',
index b361c682d40f31146d59de779a3ab4a85dd64699..befe6a8fd65a14d22081873fb1811bbe1069a878 100644 (file)
@@ -13,6 +13,7 @@ export default {
                        add: 'Add',
                        back: 'Back',
                        cancel: 'Cancel',
+                       chart: 'Chart',
                        close: 'Close',
                        edit: 'Edit',
                        help: 'Help',
@@ -43,7 +44,9 @@ export default {
                },
                icon: {
                        AddIcon: 'Add',
+                       ApplicationsIcon: 'Applications',
                        ApplyIcon: 'Apply',
+                       ChartIcon: 'Chart',
                        DiscordIcon: 'Discord',
                        EditIcon: 'Edit',
                        FinishedIcon: 'Finished',
@@ -212,6 +215,7 @@ export default {
                        noApplications: 'No applications at this point',
                        noRecord: 'Tournament set to not be recorded',
                        scoreboard: 'Scoreboard',
+                       scoreChart: 'Score chart',
                },
                users: {
                        discordTag: 'Discord tag',