x trends code, map planner bug fix and new maps
16
models/trend.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
const mongoose = require('mongoose')
|
||||
|
||||
const trendSchema = new mongoose.Schema({
|
||||
weapon: {type: String, required: true},
|
||||
counts: [
|
||||
{
|
||||
year: Number,
|
||||
SZ: [Number],
|
||||
TC: [Number],
|
||||
RM: [Number],
|
||||
CB: [Number]
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
module.exports = mongoose.model('Trend', trendSchema)
|
||||
204
react-ui/package-lock.json
generated
|
|
@ -4048,6 +4048,73 @@
|
|||
"resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz",
|
||||
"integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA="
|
||||
},
|
||||
"d3-array": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
|
||||
"integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
|
||||
},
|
||||
"d3-collection": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz",
|
||||
"integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A=="
|
||||
},
|
||||
"d3-color": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.3.0.tgz",
|
||||
"integrity": "sha512-NHODMBlj59xPAwl2BDiO2Mog6V+PrGRtBfWKqKRrs9MCqlSkIEb0Z/SfY7jW29ReHTDC/j+vwXhnZcXI3+3fbg=="
|
||||
},
|
||||
"d3-format": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.3.2.tgz",
|
||||
"integrity": "sha512-Z18Dprj96ExragQ0DeGi+SYPQ7pPfRMtUXtsg/ChVIKNBCzjO8XYJvRTC1usblx52lqge56V5ect+frYTQc8WQ=="
|
||||
},
|
||||
"d3-interpolate": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.3.2.tgz",
|
||||
"integrity": "sha512-NlNKGopqaz9qM1PXh9gBF1KSCVh+jSFErrSlD/4hybwoNX/gt1d8CDbDW+3i+5UOHhjC6s6nMvRxcuoMVNgL2w==",
|
||||
"requires": {
|
||||
"d3-color": "1"
|
||||
}
|
||||
},
|
||||
"d3-path": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.8.tgz",
|
||||
"integrity": "sha512-J6EfUNwcMQ+aM5YPOB8ZbgAZu6wc82f/0WFxrxwV6Ll8wBwLaHLKCqQ5Imub02JriCVVdPjgI+6P3a4EWJCxAg=="
|
||||
},
|
||||
"d3-scale": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz",
|
||||
"integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==",
|
||||
"requires": {
|
||||
"d3-array": "^1.2.0",
|
||||
"d3-collection": "1",
|
||||
"d3-format": "1",
|
||||
"d3-interpolate": "1",
|
||||
"d3-time": "1",
|
||||
"d3-time-format": "2"
|
||||
}
|
||||
},
|
||||
"d3-shape": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.5.tgz",
|
||||
"integrity": "sha512-VKazVR3phgD+MUCldapHD7P9kcrvPcexeX/PkMJmkUov4JM8IxsSg1DvbYoYich9AtdTsa5nNk2++ImPiDiSxg==",
|
||||
"requires": {
|
||||
"d3-path": "1"
|
||||
}
|
||||
},
|
||||
"d3-time": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.11.tgz",
|
||||
"integrity": "sha512-Z3wpvhPLW4vEScGeIMUckDW7+3hWKOQfAWg/U7PlWBnQmeKQ00gCUsTtWSYulrKNA7ta8hJ+xXc6MHrMuITwEw=="
|
||||
},
|
||||
"d3-time-format": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.1.3.tgz",
|
||||
"integrity": "sha512-6k0a2rZryzGm5Ihx+aFMuO1GgelgIz+7HhB4PH4OEndD5q2zGn1mDfRdNrulspOfR6JXkb2sThhDK41CSK85QA==",
|
||||
"requires": {
|
||||
"d3-time": "1"
|
||||
}
|
||||
},
|
||||
"damerau-levenshtein": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz",
|
||||
|
|
@ -4101,6 +4168,11 @@
|
|||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
|
||||
},
|
||||
"decimal.js-light": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.0.tgz",
|
||||
"integrity": "sha512-b3VJCbd2hwUpeRGG3Toob+CRo8W22xplipNhP3tN7TSVB/cyMX71P1vM2Xjc9H74uV6dS2hDDmo/rHq8L87Upg=="
|
||||
},
|
||||
"decode-uri-component": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
|
||||
|
|
@ -4337,6 +4409,14 @@
|
|||
"utila": "~0.4"
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"dom-serializer": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
|
||||
|
|
@ -7050,6 +7130,7 @@
|
|||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
|
|
@ -7957,6 +8038,11 @@
|
|||
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
|
||||
"integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0="
|
||||
},
|
||||
"lodash.debounce": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
|
||||
},
|
||||
"lodash.isequal": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
|
|
@ -7994,6 +8080,11 @@
|
|||
"lodash._reinterpolate": "~3.0.0"
|
||||
}
|
||||
},
|
||||
"lodash.throttle": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
|
||||
"integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
|
||||
},
|
||||
"lodash.unescape": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz",
|
||||
|
|
@ -8090,6 +8181,11 @@
|
|||
"resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz",
|
||||
"integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg=="
|
||||
},
|
||||
"math-expression-evaluator": {
|
||||
"version": "1.2.17",
|
||||
"resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz",
|
||||
"integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw="
|
||||
},
|
||||
"md5.js": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
|
||||
|
|
@ -10375,6 +10471,22 @@
|
|||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz",
|
||||
"integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA=="
|
||||
},
|
||||
"react-lifecycles-compat": {
|
||||
"version": "3.0.4",
|
||||
"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": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-2.3.0.tgz",
|
||||
"integrity": "sha512-oCAddEWWeFWYH5FAcHdBYcZjAw9fMzRUK9sWSx6WvSSOPVRxcHd5zTIGy/mOus+AhN/u6T4TMiWxvq79PywnJQ==",
|
||||
"requires": {
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"prop-types": "^15.6.0",
|
||||
"resize-observer-polyfill": "^1.5.0"
|
||||
}
|
||||
},
|
||||
"react-router": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.0.1.tgz",
|
||||
|
|
@ -10489,6 +10601,17 @@
|
|||
"react-dom": "^16.6.1"
|
||||
}
|
||||
},
|
||||
"react-smooth": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-1.0.2.tgz",
|
||||
"integrity": "sha512-pIGzL1g9VGAsRsdZQokIK0vrCkcdKtnOnS1gyB2rrowdLy69lNSWoIjCTWAfgbiYvria8tm5hEZqj+jwXMkV4A==",
|
||||
"requires": {
|
||||
"lodash": "~4.17.4",
|
||||
"prop-types": "^15.6.0",
|
||||
"raf": "^3.4.0",
|
||||
"react-transition-group": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"react-sound": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-sound/-/react-sound-1.2.0.tgz",
|
||||
|
|
@ -10498,6 +10621,17 @@
|
|||
"soundmanager2": "^2.97.20170602"
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"reactcss": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
|
||||
|
|
@ -10557,6 +10691,39 @@
|
|||
"util.promisify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"recharts": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/recharts/-/recharts-1.6.2.tgz",
|
||||
"integrity": "sha512-NqVN8Hq5wrrBthTxQB+iCnZjup1dc+AYRIB6Q9ck9UjdSJTt4PbLepGpudQEYJEN5iIpP/I2vThC4uiTJa7xUQ==",
|
||||
"requires": {
|
||||
"classnames": "^2.2.5",
|
||||
"core-js": "^2.5.1",
|
||||
"d3-interpolate": "^1.3.0",
|
||||
"d3-scale": "^2.1.0",
|
||||
"d3-shape": "^1.2.0",
|
||||
"lodash": "^4.17.5",
|
||||
"prop-types": "^15.6.0",
|
||||
"react-resize-detector": "^2.3.0",
|
||||
"react-smooth": "^1.0.0",
|
||||
"recharts-scale": "^0.4.2",
|
||||
"reduce-css-calc": "^1.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz",
|
||||
"integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"recharts-scale": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.2.tgz",
|
||||
"integrity": "sha512-p/cKt7j17D1CImLgX2f5+6IXLbRHGUQkogIp06VUoci/XkhOQiGSzUrsD1uRmiI7jha4u8XNFOjkHkzzBPivMg==",
|
||||
"requires": {
|
||||
"decimal.js-light": "^2.4.1"
|
||||
}
|
||||
},
|
||||
"recursive-readdir": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz",
|
||||
|
|
@ -10565,6 +10732,38 @@
|
|||
"minimatch": "3.0.4"
|
||||
}
|
||||
},
|
||||
"reduce-css-calc": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz",
|
||||
"integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=",
|
||||
"requires": {
|
||||
"balanced-match": "^0.4.2",
|
||||
"math-expression-evaluator": "^1.2.14",
|
||||
"reduce-function-call": "^1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"balanced-match": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
|
||||
"integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg="
|
||||
}
|
||||
}
|
||||
},
|
||||
"reduce-function-call": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.2.tgz",
|
||||
"integrity": "sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=",
|
||||
"requires": {
|
||||
"balanced-match": "^0.4.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"balanced-match": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
|
||||
"integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg="
|
||||
}
|
||||
}
|
||||
},
|
||||
"regenerate": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz",
|
||||
|
|
@ -10811,6 +11010,11 @@
|
|||
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
|
||||
},
|
||||
"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.10.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz",
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
"react-scripts": "3.0.0",
|
||||
"react-sketch": "^0.5.1",
|
||||
"react-sound": "^1.2.0",
|
||||
"recharts": "^1.6.2",
|
||||
"semantic-ui-react": "^0.86.0"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 2.1 KiB |
BIN
react-ui/public/wpnSmall/Wst_AquaBall.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
react-ui/public/wpnSmall/Wst_Bomb_Curling.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
react-ui/public/wpnSmall/Wst_Bomb_Piyo.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
react-ui/public/wpnSmall/Wst_Bomb_Quick.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
react-ui/public/wpnSmall/Wst_Bomb_Robo.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
react-ui/public/wpnSmall/Wst_Bomb_Splash.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
react-ui/public/wpnSmall/Wst_Bomb_Suction.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
react-ui/public/wpnSmall/Wst_Bomb_Tako.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
react-ui/public/wpnSmall/Wst_Flag.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
react-ui/public/wpnSmall/Wst_Jetpack.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
react-ui/public/wpnSmall/Wst_LauncherCurling.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
react-ui/public/wpnSmall/Wst_LauncherQuick.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
react-ui/public/wpnSmall/Wst_LauncherRobo.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
react-ui/public/wpnSmall/Wst_LauncherSplash.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
react-ui/public/wpnSmall/Wst_LauncherSuction.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
react-ui/public/wpnSmall/Wst_PointSensor.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
react-ui/public/wpnSmall/Wst_PoisonFog.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
react-ui/public/wpnSmall/Wst_RainCloud.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
react-ui/public/wpnSmall/Wst_Shield.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
react-ui/public/wpnSmall/Wst_Sprinkler.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
react-ui/public/wpnSmall/Wst_SuperArmor.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
react-ui/public/wpnSmall/Wst_SuperBall.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
react-ui/public/wpnSmall/Wst_SuperBubble.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
react-ui/public/wpnSmall/Wst_SuperLanding.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
react-ui/public/wpnSmall/Wst_SuperMissile.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
react-ui/public/wpnSmall/Wst_SuperStamp.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
react-ui/public/wpnSmall/Wst_TimerTrap.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
react-ui/public/wpnSmall/Wst_WaterCutter.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
10
react-ui/src/App.js
vendored
|
|
@ -12,7 +12,6 @@ import InfoWeapon from './components/XSearch/InfoWeapon'
|
|||
import ScrollToTop from './utils/ScrollToTop'
|
||||
import MapListGenerator from './components/Tools/MapListGenerator'
|
||||
import Rotations from './components/Tools/Rotations'
|
||||
import Comps from './components/Tools/Comps'
|
||||
import MapPlanner from './components/Tools/MapPlanner'
|
||||
import Links from './components/Misc/Links'
|
||||
import UserPage from './components/SoloLadder/UserPage'
|
||||
|
|
@ -20,6 +19,7 @@ import HomePage from './components/Misc/HomePage'
|
|||
import BuildSearch from './components/SoloLadder/BuildSearch'
|
||||
import Admin from './components/Misc/Admin'
|
||||
import Calendar from './components/Tools/Calendar'
|
||||
import XTrends from './components/XSearch/XTrends'
|
||||
|
||||
const App = () => {
|
||||
const [menuSelection, setMenuSelection] = useState('home')
|
||||
|
|
@ -61,9 +61,6 @@ const App = () => {
|
|||
weaponFromUrl={match.params.weapon.replace(/_/g, ' ')}
|
||||
/>
|
||||
} />
|
||||
<Route exact path="/comps" render={() =>
|
||||
<Comps />
|
||||
} />
|
||||
<Route exact path="/plans" render={() =>
|
||||
<MapPlanner
|
||||
setMenuSelection={setMenuSelection}
|
||||
|
|
@ -74,6 +71,11 @@ const App = () => {
|
|||
setMenuSelection={setMenuSelection}
|
||||
/>
|
||||
} />
|
||||
<Route exact path="/trends" render={() =>
|
||||
<XTrends
|
||||
setMenuSelection={setMenuSelection}
|
||||
/>
|
||||
} />
|
||||
<Route path="/404" render={() => <NotFound />} />
|
||||
<Route path="/admin" render={() => <Admin />} />
|
||||
<Route path="*" render={() => <NotFound />} />
|
||||
|
|
|
|||
122
react-ui/src/components/Misc/HomePage.js
vendored
|
|
@ -1,52 +1,86 @@
|
|||
import React from 'react'
|
||||
import { Header, Image } from 'semantic-ui-react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import koshienBanner from '../img/misc/koshienBanner.png'
|
||||
import React from "react"
|
||||
import { Header, Image, Segment } from "semantic-ui-react"
|
||||
import { Link } from "react-router-dom"
|
||||
import koshienBanner from "../img/misc/koshienBanner.png"
|
||||
|
||||
const HomePage = ({ setMenuSelection }) => {
|
||||
setMenuSelection('home')
|
||||
setMenuSelection("home")
|
||||
return (
|
||||
<div>
|
||||
<div style={{'textAlign': 'center'}}>
|
||||
<Header as='h2'>Welcome to sendou.ink!<Header sub>Competitive Splatoon Hub</Header></Header>
|
||||
</div>
|
||||
<div style={{'paddingTop': '20px'}}>
|
||||
<b><Link to='/plans'>Map planner</Link></b> - Draw on Splatoon 2 maps to show your teammates or anyone else what your plan is. Supports free drawing, shapes and inserting any weapon from the game on the canvas.
|
||||
</div>
|
||||
<div style={{'paddingTop': '20px'}}>
|
||||
<b><Link to='/maps'>Maplists</Link></b> - Generate a maplist to use when scrimming.
|
||||
You can choose the map pool to be used including monthly ranked maps or an upcoming event.
|
||||
Any maps you don't feel like you need to practice can be excluded from the pool.
|
||||
</div>
|
||||
<div style={{'paddingTop': '15px'}}>
|
||||
<b><Link to='/rotation'>Rotation</Link></b> - View upcoming Splatoon 2 rotations up to 24 hours in advance.
|
||||
Have some maps you'd rather not play in ranked? You can set those as unfavored maps (log in not required).
|
||||
If a rotation contains your unfavored maps you can easily tell at a glance.
|
||||
</div>
|
||||
<div style={{'paddingTop': '15px'}}>
|
||||
<b><Link to='/xleaderboard'>Leaderboards</Link></b> - Browse through X Rank Top 500 Leaderboards.
|
||||
There is a leaderboard for each weapon class where players are ranked by the average of their top four powers.
|
||||
</div>
|
||||
<div style={{'paddingTop': '15px'}}>
|
||||
<b><Link to='/xsearch'>Top 500 Search</Link></b> - Search through X Rank Top 500 results.
|
||||
You can choose any weapon to find out the top performing players with it.
|
||||
Another way is to search for a player name if you are curious how a specific player has performed in the past.
|
||||
</div>
|
||||
<div style={{'paddingTop': '15px'}}>
|
||||
<b><Link to='/calendar'>Calendar</Link></b> - Discover all the upcoming events in competitive Splatoon.
|
||||
</div>
|
||||
<div style={{'paddingTop': '15px'}}>
|
||||
<b><Link to='/links'>Links</Link></b> - Discover useful resources related to competitive Splatoon.
|
||||
</div>
|
||||
<div style={{'paddingTop': '15px'}}>
|
||||
If you <b>login</b> you can add gear builds on your user page. As a reference you can take a look at
|
||||
my <Link to='u/79237403620945920'>page.</Link>
|
||||
</div>
|
||||
<div style={{'paddingTop': '10px'}}>
|
||||
<Image rounded src={koshienBanner} size='huge' centered/>
|
||||
</div>
|
||||
<Segment>
|
||||
<div style={{"padding": "5px"}}>
|
||||
<div style={{ textAlign: "center"}}>
|
||||
<Header as="h2">
|
||||
Welcome to sendou.ink!<Header sub>Competitive Splatoon Hub</Header>
|
||||
</Header>
|
||||
</div>
|
||||
<div style={{ paddingTop: "20px" }}>
|
||||
<b>
|
||||
<Link to="/plans">Map planner</Link>
|
||||
</b>{" "}
|
||||
- Draw on Splatoon 2 maps to show your teammates or anyone else what
|
||||
your plan is. Supports free drawing, shapes and inserting any weapon
|
||||
from the game on the canvas.
|
||||
</div>
|
||||
<div style={{ paddingTop: "20px" }}>
|
||||
<b>
|
||||
<Link to="/maps">Maplists</Link>
|
||||
</b>{" "}
|
||||
- Generate a maplist to use when scrimming. You can choose the map
|
||||
pool to be used including monthly ranked maps or an upcoming event.
|
||||
Any maps you don't feel like you need to practice can be excluded from
|
||||
the pool.
|
||||
</div>
|
||||
<div style={{ paddingTop: "15px" }}>
|
||||
<b>
|
||||
<Link to="/rotation">Rotation</Link>
|
||||
</b>{" "}
|
||||
- View upcoming Splatoon 2 rotations up to 24 hours in advance. Have
|
||||
some maps you'd rather not play in ranked? You can set those as
|
||||
unfavored maps (log in not required). If a rotation contains your
|
||||
unfavored maps you can easily tell at a glance.
|
||||
</div>
|
||||
<div style={{ paddingTop: "15px" }}>
|
||||
<b>
|
||||
<Link to="/xleaderboard">Leaderboards</Link>
|
||||
</b>{" "}
|
||||
- Browse through X Rank Top 500 Leaderboards. There is a leaderboard
|
||||
for each weapon class where players are ranked by the average of their
|
||||
top four powers.
|
||||
</div>
|
||||
<div style={{ paddingTop: "15px" }}>
|
||||
<b>
|
||||
<Link to="/xsearch">Top 500 Search</Link>
|
||||
</b>{" "}
|
||||
- Search through X Rank Top 500 results. You can choose any weapon to
|
||||
find out the top performing players with it. Another way is to search
|
||||
for a player name if you are curious how a specific player has
|
||||
performed in the past.
|
||||
</div>
|
||||
<div style={{ paddingTop: "15px" }}>
|
||||
<b>
|
||||
<Link to="/calendar">Calendar</Link>
|
||||
</b>{" "}
|
||||
- Discover all the upcoming events in competitive Splatoon.
|
||||
</div>
|
||||
<div style={{ paddingTop: "15px" }}>
|
||||
<b>
|
||||
<Link to="/links">Links</Link>
|
||||
</b>{" "}
|
||||
- Discover useful resources related to competitive Splatoon.
|
||||
</div>
|
||||
<div style={{ paddingTop: "15px" }}>
|
||||
If you <b>login</b> you can add gear builds on your user page. As a
|
||||
reference you can take a look at my{" "}
|
||||
<Link to="u/79237403620945920">page.</Link>
|
||||
</div>
|
||||
<div style={{ paddingTop: "10px" }}>
|
||||
<Image rounded src={koshienBanner} size="huge" centered />
|
||||
</div>
|
||||
</div>
|
||||
</Segment>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default HomePage
|
||||
export default HomePage
|
||||
|
|
|
|||
154
react-ui/src/components/Misc/Links.js
vendored
|
|
@ -1,89 +1,97 @@
|
|||
import React from 'react'
|
||||
import { Icon, Header, Loader, List } from 'semantic-ui-react'
|
||||
import { useQuery } from 'react-apollo-hooks'
|
||||
import { links } from '../../graphql/queries/links'
|
||||
import React from "react"
|
||||
import { Icon, Header, Loader, List, Segment } from "semantic-ui-react"
|
||||
import { useQuery } from "react-apollo-hooks"
|
||||
import { links } from "../../graphql/queries/links"
|
||||
|
||||
const Links = ({ setMenuSelection }) => {
|
||||
const { data, error, loading } = useQuery(links)
|
||||
|
||||
setMenuSelection('links')
|
||||
document.title = 'Links - sendou.ink'
|
||||
setMenuSelection("links")
|
||||
document.title = "Links - sendou.ink"
|
||||
|
||||
if (loading) {
|
||||
return <div style={{"paddingTop": "25px", "paddingBottom": "20000px"}} ><Loader active inline='centered' /></div>
|
||||
return (
|
||||
<div style={{ paddingTop: "25px", paddingBottom: "20000px" }}>
|
||||
<Loader active inline="centered" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
if (error) {
|
||||
return <div style={{"color": "red"}}>{error.message}</div>
|
||||
return <div style={{ color: "red" }}>{error.message}</div>
|
||||
}
|
||||
const linksData = data.links
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{'paddingTop': '10px'}}>
|
||||
<Header as='h1'>
|
||||
<Icon name='discord' />
|
||||
<Header.Content>Discord</Header.Content>
|
||||
</Header>
|
||||
<List divided verticalAlign='middle'>
|
||||
{linksData.map(l => {
|
||||
if (l.type !== 'DISCORD') {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<List.Item key={l.title} style={{'padding': '6px'}}>
|
||||
<List.Header size='small' as='a' href={l.url}>{l.title}</List.Header>
|
||||
<List.Description>
|
||||
{l.description}
|
||||
</List.Description>
|
||||
</List.Item>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
<div>
|
||||
<Segment>
|
||||
<div style={{ padding: "5px" }}>
|
||||
<div style={{ paddingTop: "10px" }}>
|
||||
<Header as="h1">
|
||||
<Icon name="discord" />
|
||||
<Header.Content>Discord</Header.Content>
|
||||
</Header>
|
||||
<List divided verticalAlign="middle">
|
||||
{linksData.map(l => {
|
||||
if (l.type !== "DISCORD") {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<List.Item key={l.title} style={{ padding: "6px" }}>
|
||||
<List.Header size="small" as="a" href={l.url}>
|
||||
{l.title}
|
||||
</List.Header>
|
||||
<List.Description>{l.description}</List.Description>
|
||||
</List.Item>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
</div>
|
||||
<div style={{ paddingTop: "20px" }}>
|
||||
<Header as="h1">
|
||||
<Icon name="book" />
|
||||
<Header.Content>Guides</Header.Content>
|
||||
</Header>
|
||||
<List divided verticalAlign="middle">
|
||||
{linksData.map(l => {
|
||||
if (l.type !== "GUIDE") {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<List.Item key={l.title} style={{ padding: "6px" }}>
|
||||
<List.Header size="small" as="a" href={l.url}>
|
||||
{l.title}
|
||||
</List.Header>
|
||||
<List.Description>{l.description}</List.Description>
|
||||
</List.Item>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
</div>
|
||||
<div style={{ paddingTop: "20px" }}>
|
||||
<Header as="h1">
|
||||
<Icon name="folder open" />
|
||||
<Header.Content>Misc</Header.Content>
|
||||
</Header>
|
||||
<List divided verticalAlign="middle">
|
||||
{linksData.map(l => {
|
||||
if (l.type !== "MISC") {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<List.Item key={l.title} style={{ padding: "6px" }}>
|
||||
<List.Header size="small" as="a" href={l.url}>
|
||||
{l.title}
|
||||
</List.Header>
|
||||
<List.Description>{l.description}</List.Description>
|
||||
</List.Item>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
</div>
|
||||
</div>
|
||||
</Segment>
|
||||
</div>
|
||||
<div style={{'paddingTop': '20px'}}>
|
||||
<Header as='h1'>
|
||||
<Icon name='book' />
|
||||
<Header.Content>Guides</Header.Content>
|
||||
</Header>
|
||||
<List divided verticalAlign='middle'>
|
||||
{linksData.map(l => {
|
||||
if (l.type !== 'GUIDE') {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<List.Item key={l.title} style={{'padding': '6px'}}>
|
||||
<List.Header size='small' as='a' href={l.url}>{l.title}</List.Header>
|
||||
<List.Description>
|
||||
{l.description}
|
||||
</List.Description>
|
||||
</List.Item>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
</div>
|
||||
<div style={{'paddingTop': '20px'}}>
|
||||
<Header as='h1'>
|
||||
<Icon name='folder open' />
|
||||
<Header.Content>Misc</Header.Content>
|
||||
</Header>
|
||||
<List divided verticalAlign='middle'>
|
||||
{linksData.map(l => {
|
||||
if (l.type !== 'MISC') {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<List.Item key={l.title} style={{'padding': '6px'}}>
|
||||
<List.Header size='small' as='a' href={l.url}>{l.title}</List.Header>
|
||||
<List.Description>
|
||||
{l.description}
|
||||
</List.Description>
|
||||
</List.Item>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Links
|
||||
export default Links
|
||||
|
|
|
|||
5
react-ui/src/components/Misc/MainMenu.js
vendored
|
|
@ -109,6 +109,11 @@ const MainMenu = withRouter(({ history, menuSelection, setMenuSelection }) => {
|
|||
active={menuSelection === 'search'}
|
||||
onClick={() => { history.push('/xsearch') }}
|
||||
/>
|
||||
<Menu.Item
|
||||
name='trends'
|
||||
active={menuSelection === 'trends'}
|
||||
onClick={() => { history.push('/trends') }}
|
||||
/>
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
<Menu.Item
|
||||
|
|
|
|||
417
react-ui/src/components/Misc/RollSim.js
vendored
|
|
@ -1,100 +1,174 @@
|
|||
import React, { useState } from 'react'
|
||||
import { Grid, Comment } from 'semantic-ui-react'
|
||||
import { clothingGear, shoesGear, headGear, choose } from '../../utils/lists'
|
||||
import Sound from 'react-sound'
|
||||
import useWindowDimensions from '../hooks/useWindowDimensions'
|
||||
import React, { useState } from "react"
|
||||
import { Grid, Comment } from "semantic-ui-react"
|
||||
import { clothingGear, shoesGear, headGear, choose } from "../../utils/lists"
|
||||
import Sound from "react-sound"
|
||||
import useWindowDimensions from "../hooks/useWindowDimensions"
|
||||
|
||||
import BDU from '../img/abilityIcons/BDU.png'
|
||||
import BRU from '../img/abilityIcons/BRU.png'
|
||||
import CB from '../img/abilityIcons/CB.png'
|
||||
import DR from '../img/abilityIcons/DR.png'
|
||||
import H from '../img/abilityIcons/H.png'
|
||||
import ISM from '../img/abilityIcons/ISM.png'
|
||||
import ISS from '../img/abilityIcons/ISS.png'
|
||||
import LDE from '../img/abilityIcons/LDE.png'
|
||||
import MPU from '../img/abilityIcons/MPU.png'
|
||||
import NS from '../img/abilityIcons/NS.png'
|
||||
import OG from '../img/abilityIcons/OG.png'
|
||||
import QR from '../img/abilityIcons/QR.png'
|
||||
import QSJ from '../img/abilityIcons/QSJ.png'
|
||||
import REC from '../img/abilityIcons/REC.png'
|
||||
import RES from '../img/abilityIcons/RES.png'
|
||||
import RP from '../img/abilityIcons/RP.png'
|
||||
import RSU from '../img/abilityIcons/RSU.png'
|
||||
import SCU from '../img/abilityIcons/SCU.png'
|
||||
import SJ from '../img/abilityIcons/SJ.png'
|
||||
import SPU from '../img/abilityIcons/SPU.png'
|
||||
import SS from '../img/abilityIcons/SS.png'
|
||||
import SSU from '../img/abilityIcons/SSU.png'
|
||||
import T from '../img/abilityIcons/T.png'
|
||||
import TI from '../img/abilityIcons/TI.png'
|
||||
import OS from '../img/abilityIcons/OS.png'
|
||||
import murchpfp from '../img/misc/murchpfp.png'
|
||||
import reroll from '../sounds/reroll.mp3'
|
||||
import booyah from '../sounds/nice.mp3'
|
||||
import head from '../../utils/head.json'
|
||||
import clothes from '../../utils/clothes.json'
|
||||
import shoes from '../../utils/shoes.json'
|
||||
import BDU from "../img/abilityIcons/BDU.png"
|
||||
import BRU from "../img/abilityIcons/BRU.png"
|
||||
import CB from "../img/abilityIcons/CB.png"
|
||||
import DR from "../img/abilityIcons/DR.png"
|
||||
import H from "../img/abilityIcons/H.png"
|
||||
import ISM from "../img/abilityIcons/ISM.png"
|
||||
import ISS from "../img/abilityIcons/ISS.png"
|
||||
import LDE from "../img/abilityIcons/LDE.png"
|
||||
import MPU from "../img/abilityIcons/MPU.png"
|
||||
import NS from "../img/abilityIcons/NS.png"
|
||||
import OG from "../img/abilityIcons/OG.png"
|
||||
import QR from "../img/abilityIcons/QR.png"
|
||||
import QSJ from "../img/abilityIcons/QSJ.png"
|
||||
import REC from "../img/abilityIcons/REC.png"
|
||||
import RES from "../img/abilityIcons/RES.png"
|
||||
import RP from "../img/abilityIcons/RP.png"
|
||||
import RSU from "../img/abilityIcons/RSU.png"
|
||||
import SCU from "../img/abilityIcons/SCU.png"
|
||||
import SJ from "../img/abilityIcons/SJ.png"
|
||||
import SPU from "../img/abilityIcons/SPU.png"
|
||||
import SS from "../img/abilityIcons/SS.png"
|
||||
import SSU from "../img/abilityIcons/SSU.png"
|
||||
import T from "../img/abilityIcons/T.png"
|
||||
import TI from "../img/abilityIcons/TI.png"
|
||||
import OS from "../img/abilityIcons/OS.png"
|
||||
import murchpfp from "../img/misc/murchpfp.png"
|
||||
import reroll from "../sounds/reroll.mp3"
|
||||
import booyah from "../sounds/nice.mp3"
|
||||
import head from "../../utils/head.json"
|
||||
import clothes from "../../utils/clothes.json"
|
||||
import shoes from "../../utils/shoes.json"
|
||||
|
||||
const mainAbilityStyle = { //https://github.com/loadout-ink/splat2-calc
|
||||
"zIndex": "2",
|
||||
"borderRadius": "50%",
|
||||
"width": "40px",
|
||||
"height": "40px",
|
||||
"background": "#000",
|
||||
"border": "2px solid #888",
|
||||
"borderRight": "0px",
|
||||
"borderBottom": "0px",
|
||||
"backgroundSize": "100%",
|
||||
"boxShadow": "0 0 0 1px #000"
|
||||
const mainAbilityStyle = {
|
||||
//https://github.com/loadout-ink/splat2-calc
|
||||
zIndex: "2",
|
||||
borderRadius: "50%",
|
||||
width: "40px",
|
||||
height: "40px",
|
||||
background: "#000",
|
||||
border: "2px solid #888",
|
||||
borderRight: "0px",
|
||||
borderBottom: "0px",
|
||||
backgroundSize: "100%",
|
||||
boxShadow: "0 0 0 1px #000"
|
||||
}
|
||||
const subAbilityStyle = { //https://github.com/loadout-ink/splat2-calc
|
||||
"zIndex": "2",
|
||||
"borderRadius": "50%",
|
||||
"width": "30px",
|
||||
"height": "30px",
|
||||
"background": "#000",
|
||||
"border": "2px solid #888",
|
||||
"borderRight": "0px",
|
||||
"borderBottom": "0px",
|
||||
"backgroundSize": "100%",
|
||||
"boxShadow": "0 0 0 1px #000"
|
||||
const subAbilityStyle = {
|
||||
//https://github.com/loadout-ink/splat2-calc
|
||||
zIndex: "2",
|
||||
borderRadius: "50%",
|
||||
width: "30px",
|
||||
height: "30px",
|
||||
background: "#000",
|
||||
border: "2px solid #888",
|
||||
borderRight: "0px",
|
||||
borderBottom: "0px",
|
||||
backgroundSize: "100%",
|
||||
boxShadow: "0 0 0 1px #000"
|
||||
}
|
||||
const speechBubble = {
|
||||
"content": '',
|
||||
"position": "absolute",
|
||||
"left": "0",
|
||||
"top": "50%",
|
||||
"width": "0",
|
||||
"height": "0",
|
||||
"border": "26px solid transparent",
|
||||
"borderRightColor": "#000000",
|
||||
"borderLeft": "0",
|
||||
"marginTop": "-26px",
|
||||
"marginLeft": "-26px",
|
||||
}
|
||||
const gearStyle = { "maxWidth": "50px", "height": "auto" }
|
||||
const gearStyle = { maxWidth: "50px", height: "auto" }
|
||||
|
||||
const subAbilities = [ISM,ISS,REC,RSU,SSU,QSJ,RES,BDU,MPU,QR,SCU,SS,SPU,BRU,ISM,ISS,REC,RSU,SSU,QSJ,RES,BDU,MPU,QR,SCU,SS,SPU,BRU]
|
||||
const headAbilities = [ISM,ISS,REC,RSU,SSU,QSJ,RES,BDU,MPU,QR,SCU,SS,SPU,BRU,OG,LDE,CB,T]
|
||||
const clothingAbilities = [ISM,ISS,REC,RSU,SSU,QSJ,RES,BDU,MPU,QR,SCU,SS,SPU,BRU,H,NS,TI,RP]
|
||||
const shoeAbilities = [ISM,ISS,REC,RSU,SSU,QSJ,RES,BDU,MPU,QR,SCU,SS,SPU,BRU,DR,SJ,OS]
|
||||
const subAbilities = [
|
||||
ISM,
|
||||
ISS,
|
||||
REC,
|
||||
RSU,
|
||||
SSU,
|
||||
QSJ,
|
||||
RES,
|
||||
BDU,
|
||||
MPU,
|
||||
QR,
|
||||
SCU,
|
||||
SS,
|
||||
SPU,
|
||||
BRU,
|
||||
ISM,
|
||||
ISS,
|
||||
REC,
|
||||
RSU,
|
||||
SSU,
|
||||
QSJ,
|
||||
RES,
|
||||
BDU,
|
||||
MPU,
|
||||
QR,
|
||||
SCU,
|
||||
SS,
|
||||
SPU,
|
||||
BRU
|
||||
]
|
||||
const headAbilities = [
|
||||
ISM,
|
||||
ISS,
|
||||
REC,
|
||||
RSU,
|
||||
SSU,
|
||||
QSJ,
|
||||
RES,
|
||||
BDU,
|
||||
MPU,
|
||||
QR,
|
||||
SCU,
|
||||
SS,
|
||||
SPU,
|
||||
BRU,
|
||||
OG,
|
||||
LDE,
|
||||
CB,
|
||||
T
|
||||
]
|
||||
const clothingAbilities = [
|
||||
ISM,
|
||||
ISS,
|
||||
REC,
|
||||
RSU,
|
||||
SSU,
|
||||
QSJ,
|
||||
RES,
|
||||
BDU,
|
||||
MPU,
|
||||
QR,
|
||||
SCU,
|
||||
SS,
|
||||
SPU,
|
||||
BRU,
|
||||
H,
|
||||
NS,
|
||||
TI,
|
||||
RP
|
||||
]
|
||||
const shoeAbilities = [
|
||||
ISM,
|
||||
ISS,
|
||||
REC,
|
||||
RSU,
|
||||
SSU,
|
||||
QSJ,
|
||||
RES,
|
||||
BDU,
|
||||
MPU,
|
||||
QR,
|
||||
SCU,
|
||||
SS,
|
||||
SPU,
|
||||
BRU,
|
||||
DR,
|
||||
SJ,
|
||||
OS
|
||||
]
|
||||
|
||||
const internalToAbility = {
|
||||
"MainInk_Save": ISM,
|
||||
"SubInk_Save": ISS,
|
||||
"InkRecovery_Up": REC,
|
||||
"HumanMove_Up": RSU,
|
||||
"SquidMove_Up": SSU,
|
||||
"JumpTime_Save": QSJ,
|
||||
"RespawnTime_Save": QR,
|
||||
"OpInkEffect_Reduction": RES,
|
||||
"BombDamage_Reduction": BDU,
|
||||
"MarkingTime_Reduction": MPU,
|
||||
"RespawnSpecialGauge_Save": SS,
|
||||
"SpecialIncrease_Up": SCU,
|
||||
"SpecialTime_Up": SPU,
|
||||
"BombDistance_Up": BRU
|
||||
MainInk_Save: ISM,
|
||||
SubInk_Save: ISS,
|
||||
InkRecovery_Up: REC,
|
||||
HumanMove_Up: RSU,
|
||||
SquidMove_Up: SSU,
|
||||
JumpTime_Save: QSJ,
|
||||
RespawnTime_Save: QR,
|
||||
OpInkEffect_Reduction: RES,
|
||||
BombDamage_Reduction: BDU,
|
||||
MarkingTime_Reduction: MPU,
|
||||
RespawnSpecialGauge_Save: SS,
|
||||
SpecialIncrease_Up: SCU,
|
||||
SpecialTime_Up: SPU,
|
||||
BombDistance_Up: BRU
|
||||
}
|
||||
|
||||
const RollSim = () => {
|
||||
|
|
@ -104,20 +178,34 @@ const RollSim = () => {
|
|||
const [audio, setAudio] = useState(Sound.status.STOPPED)
|
||||
const [nice, setNice] = useState(Sound.status.STOPPED)
|
||||
const [headMain] = useState(choose(headAbilities))
|
||||
const [headSubs, setHeadSubs] = useState([choose(subAbilities), choose(subAbilities), choose(subAbilities)])
|
||||
const [headSubs, setHeadSubs] = useState([
|
||||
choose(subAbilities),
|
||||
choose(subAbilities),
|
||||
choose(subAbilities)
|
||||
])
|
||||
const [clothingMain] = useState(choose(clothingAbilities))
|
||||
const [clothingSubs, setClothingSubs] = useState([choose(subAbilities), choose(subAbilities), choose(subAbilities)])
|
||||
const [clothingSubs, setClothingSubs] = useState([
|
||||
choose(subAbilities),
|
||||
choose(subAbilities),
|
||||
choose(subAbilities)
|
||||
])
|
||||
const [shoesMain] = useState(choose(shoeAbilities))
|
||||
const [shoesSubs, setShoesSubs] = useState([choose(subAbilities), choose(subAbilities), choose(subAbilities)])
|
||||
const [shoesSubs, setShoesSubs] = useState([
|
||||
choose(subAbilities),
|
||||
choose(subAbilities),
|
||||
choose(subAbilities)
|
||||
])
|
||||
const [rolling, setRolling] = useState(false)
|
||||
const [rollCount, setRollCount] = useState(0)
|
||||
const { containerWidth } = useWindowDimensions()
|
||||
|
||||
const setSubs = (json, gear) => {
|
||||
let gearName = gear.split("_")[1]
|
||||
if (!json.hasOwnProperty(gearName)) return [choose(subAbilities), choose(subAbilities), choose(subAbilities)]
|
||||
if (!json.hasOwnProperty(gearName))
|
||||
return [choose(subAbilities), choose(subAbilities), choose(subAbilities)]
|
||||
const prefArray = json[gearName]
|
||||
if (prefArray[0] === prefArray[1]) { //neutral brand
|
||||
if (prefArray[0] === prefArray[1]) {
|
||||
//neutral brand
|
||||
return [choose(subAbilities), choose(subAbilities), choose(subAbilities)]
|
||||
}
|
||||
|
||||
|
|
@ -140,16 +228,17 @@ const RollSim = () => {
|
|||
const ability1 = choose(adjustedAbilities)
|
||||
const ability2 = choose(adjustedAbilities)
|
||||
const ability3 = choose(adjustedAbilities)
|
||||
if (ability1 === ability2 && ability1 === ability3) setNice(Sound.status.PLAYING)
|
||||
if (ability1 === ability2 && ability1 === ability3)
|
||||
setNice(Sound.status.PLAYING)
|
||||
|
||||
return [ability1, ability2, ability3]
|
||||
}
|
||||
|
||||
const sleep = (milliseconds) => {
|
||||
const sleep = milliseconds => {
|
||||
return new Promise(resolve => setTimeout(resolve, milliseconds))
|
||||
}
|
||||
|
||||
const roll = async (mode) => {
|
||||
|
||||
const roll = async mode => {
|
||||
if (rolling) return
|
||||
|
||||
let setSubsState = null
|
||||
|
|
@ -184,58 +273,122 @@ const RollSim = () => {
|
|||
setSubsState(setSubs(json, gear)) //only using this method in the last roll that matters for optimization purposes
|
||||
setAudio(Sound.status.STOPPED)
|
||||
setRolling(false)
|
||||
setRollCount(rollCount+1)
|
||||
setRollCount(rollCount + 1)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Sound url={reroll} playStatus={audio} loop={true} volume={10} />
|
||||
<Sound url={booyah} playStatus={nice} volume={10} onFinishedPlaying={() => setNice(Sound.status.STOPPED)} />
|
||||
<Grid columns='equal' stackable>
|
||||
<Sound
|
||||
url={booyah}
|
||||
playStatus={nice}
|
||||
volume={10}
|
||||
onFinishedPlaying={() => setNice(Sound.status.STOPPED)}
|
||||
/>
|
||||
<Grid columns="equal" stackable>
|
||||
<Grid.Row>
|
||||
<Grid.Column textAlign={containerWidth < 768 ? null : "left"}>
|
||||
<div style={{'float': 'none', 'whiteSpace': 'nowrap'}}>
|
||||
<img src={`https://raw.githubusercontent.com/Leanny/leanny.github.io/master/splat2/gear/${headLink}.png`} style={gearStyle} alt="" />
|
||||
<img src={headMain} style={mainAbilityStyle} alt=""/>
|
||||
<img src={headSubs[0]} style={subAbilityStyle} onClick={() => roll("HEAD")} alt="" />
|
||||
<img src={headSubs[1]} style={subAbilityStyle} onClick={() => roll("HEAD")} alt="" />
|
||||
<img src={headSubs[2]} style={subAbilityStyle} onClick={() => roll("HEAD")} alt="" />
|
||||
<div style={{ float: "none", whiteSpace: "nowrap" }}>
|
||||
<img
|
||||
src={`https://raw.githubusercontent.com/Leanny/leanny.github.io/master/splat2/gear/${headLink}.png`}
|
||||
style={gearStyle}
|
||||
alt=""
|
||||
/>
|
||||
<img src={headMain} style={mainAbilityStyle} alt="" />
|
||||
<img
|
||||
src={headSubs[0]}
|
||||
style={subAbilityStyle}
|
||||
onClick={() => roll("HEAD")}
|
||||
alt=""
|
||||
/>
|
||||
<img
|
||||
src={headSubs[1]}
|
||||
style={subAbilityStyle}
|
||||
onClick={() => roll("HEAD")}
|
||||
alt=""
|
||||
/>
|
||||
<img
|
||||
src={headSubs[2]}
|
||||
style={subAbilityStyle}
|
||||
onClick={() => roll("HEAD")}
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
</Grid.Column>
|
||||
<Grid.Column textAlign={containerWidth < 768 ? null : "center"}>
|
||||
<div style={{'float': 'none', 'whiteSpace': 'nowrap'}}>
|
||||
<img src={`https://raw.githubusercontent.com/Leanny/leanny.github.io/master/splat2/gear/${clothingLink}.png`} style={gearStyle} alt="" />
|
||||
<div style={{ float: "none", whiteSpace: "nowrap" }}>
|
||||
<img
|
||||
src={`https://raw.githubusercontent.com/Leanny/leanny.github.io/master/splat2/gear/${clothingLink}.png`}
|
||||
style={gearStyle}
|
||||
alt=""
|
||||
/>
|
||||
<img src={clothingMain} style={mainAbilityStyle} alt="" />
|
||||
<img src={clothingSubs[0]} style={subAbilityStyle} alt="" onClick={() => roll("CLOTHING")} />
|
||||
<img src={clothingSubs[1]} style={subAbilityStyle} alt="" onClick={() => roll("CLOTHING")} />
|
||||
<img src={clothingSubs[2]} style={subAbilityStyle} alt="" onClick={() => roll("CLOTHING")} />
|
||||
<img
|
||||
src={clothingSubs[0]}
|
||||
style={subAbilityStyle}
|
||||
alt=""
|
||||
onClick={() => roll("CLOTHING")}
|
||||
/>
|
||||
<img
|
||||
src={clothingSubs[1]}
|
||||
style={subAbilityStyle}
|
||||
alt=""
|
||||
onClick={() => roll("CLOTHING")}
|
||||
/>
|
||||
<img
|
||||
src={clothingSubs[2]}
|
||||
style={subAbilityStyle}
|
||||
alt=""
|
||||
onClick={() => roll("CLOTHING")}
|
||||
/>
|
||||
</div>
|
||||
</Grid.Column>
|
||||
<Grid.Column textAlign={containerWidth < 768 ? null : "right"}>
|
||||
<div style={{'float': 'none', 'whiteSpace': 'nowrap'}}>
|
||||
<img src={`https://raw.githubusercontent.com/Leanny/leanny.github.io/master/splat2/gear/${shoesLink}.png`} style={gearStyle} alt="" />
|
||||
<img src={shoesMain} style={mainAbilityStyle} alt=""/>
|
||||
<img src={shoesSubs[0]} style={subAbilityStyle} alt="" onClick={() => roll("SHOES")} />
|
||||
<img src={shoesSubs[1]} style={subAbilityStyle} alt="" onClick={() => roll("SHOES")} />
|
||||
<img src={shoesSubs[2]} style={subAbilityStyle} alt="" onClick={() => roll("SHOES")} />
|
||||
<div style={{ float: "none", whiteSpace: "nowrap" }}>
|
||||
<img
|
||||
src={`https://raw.githubusercontent.com/Leanny/leanny.github.io/master/splat2/gear/${shoesLink}.png`}
|
||||
style={gearStyle}
|
||||
alt=""
|
||||
/>
|
||||
<img src={shoesMain} style={mainAbilityStyle} alt="" />
|
||||
<img
|
||||
src={shoesSubs[0]}
|
||||
style={subAbilityStyle}
|
||||
alt=""
|
||||
onClick={() => roll("SHOES")}
|
||||
/>
|
||||
<img
|
||||
src={shoesSubs[1]}
|
||||
style={subAbilityStyle}
|
||||
alt=""
|
||||
onClick={() => roll("SHOES")}
|
||||
/>
|
||||
<img
|
||||
src={shoesSubs[2]}
|
||||
style={subAbilityStyle}
|
||||
alt=""
|
||||
onClick={() => roll("SHOES")}
|
||||
/>
|
||||
</div>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
{rollCount > 0 &&
|
||||
<Comment.Group>
|
||||
<Comment>
|
||||
<Comment.Avatar as='a' src={murchpfp} />
|
||||
<Comment.Content>
|
||||
<Comment.Author>Murch</Comment.Author>
|
||||
<Comment.Text>
|
||||
You have rolled {rollCount} {rollCount === 1 ? "time" : "times"}, chum.
|
||||
</Comment.Text>
|
||||
</Comment.Content>
|
||||
</Comment>
|
||||
</Comment.Group>}
|
||||
{rollCount > 0 && (
|
||||
<Comment.Group>
|
||||
<Comment>
|
||||
<Comment.Avatar as="a" src={murchpfp} />
|
||||
<Comment.Content>
|
||||
<Comment.Author>Murch</Comment.Author>
|
||||
<Comment.Text>
|
||||
You have rolled {rollCount} {rollCount === 1 ? "time" : "times"}
|
||||
, chum.
|
||||
</Comment.Text>
|
||||
</Comment.Content>
|
||||
</Comment>
|
||||
</Comment.Group>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default RollSim
|
||||
export default RollSim
|
||||
|
|
|
|||
69
react-ui/src/components/Tools/Comps.js
vendored
|
|
@ -1,69 +0,0 @@
|
|||
import React from 'react'
|
||||
import Tournament from './Tournament'
|
||||
|
||||
const Comps = () => {
|
||||
const mockData = [{
|
||||
id: 'a',
|
||||
name: "In The Zone X",
|
||||
bracket: "https://sendous.challonge.com/InTheZone10",
|
||||
vod: "https://www.twitch.tv/videos/446387554",
|
||||
weapons: ["Heavy Splatling Remix", "Tenta Camo Brella", "Tentatek Splattershot", "Soda Slosher", "Splattershot Jr.", "Kensa Splattershot Pro", "Splatterscope", "Custom Dualie Squelchers", "Splat Brella", "Firefin Splatterscope", "Kensa Splattershot"],
|
||||
team_count: 42,
|
||||
japanese: false,
|
||||
patch: '4.9.0',
|
||||
timestamp: 1561852800,
|
||||
alpha_team: ["15919661737096779013", "17188550932108025730", "14175924256374209434", "10344205398411576675",], //either uids or nicknames order matters kaji plontro grey kiver
|
||||
bravo_team: ["12385180454540543327", "14434881234947959524", "15316460862005315247", "7140457213492687321"], //erza brian sorin zekken
|
||||
alpha_team_players: ["Kaji", "plontro", "Grey", "Kiver"],
|
||||
bravo_team_players: ["Erza", "Brian", "Sorin", "Zekken"],
|
||||
alpha_team_name: ["Kraken Paradise"],
|
||||
bravo_team_name: ["Team Olive"],
|
||||
rounds: [{
|
||||
winner: "BRAVO", //enum
|
||||
map: "MakoMart",
|
||||
mode: "Splat Zones", //enum
|
||||
alpha_weapons: ["Heavy Splatling Remix", "Soda Slosher", "Splattershot Jr.", "Kensa Splattershot Pro"],
|
||||
bravo_weapons: ["Soda Slosher", "Splatterscope", "Splattershot Jr.", "Kensa Splattershot Pro"]
|
||||
},
|
||||
{
|
||||
winner: "BRAVO", //enum
|
||||
map: "Wahoo World",
|
||||
mode: "Splat Zones", //enum
|
||||
alpha_weapons: ["Heavy Splatling Remix", "Soda Slosher", "Splattershot Jr.", "Custom Dualie Squelchers"],
|
||||
bravo_weapons: ["Splat Brella", "Firefin Splatterscope", "Splattershot Jr.", "Kensa Splattershot"]
|
||||
},
|
||||
{
|
||||
winner: "ALPHA",
|
||||
map: "Skipper Pavilion",
|
||||
mode: "Splat Zones",
|
||||
alpha_weapons: ["Heavy Splatling Remix", "Soda Slosher", "Tenta Camo Brella", "Custom Dualie Squelchers"],
|
||||
bravo_weapons: ["Kensa Sloshing Machine", "Splatterscope", "Splattershot Jr.", "Kensa Splattershot Pro"]
|
||||
},
|
||||
{
|
||||
winner: "BRAVO",
|
||||
map: "Manta Maria",
|
||||
mode: "Splat Zones",
|
||||
alpha_weapons: ["Heavy Splatling Remix", "Soda Slosher", "Tenta Camo Brella", "Tentatek Splattershot"],
|
||||
bravo_weapons: ["Splat Brella", "Firefin Splatterscope", "Splattershot Jr.", "Kensa Splattershot"]
|
||||
}]
|
||||
}]
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
Search bar here.
|
||||
</div>
|
||||
<div>
|
||||
{mockData.map(t => {
|
||||
return (
|
||||
<Tournament tournament={t} key={t.id}/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
Pagination here
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Comps
|
||||
476
react-ui/src/components/Tools/MapListGenerator.js
vendored
|
|
@ -1,62 +1,79 @@
|
|||
import React, { useEffect, useState, useRef } from 'react'
|
||||
import { Loader, Checkbox, Form, Header, List, Image, Divider, Icon, Grid, Input, Button, Label } from 'semantic-ui-react'
|
||||
import { useQuery } from 'react-apollo-hooks'
|
||||
import { maplists } from '../../graphql/queries/maplists'
|
||||
import szIcon from '../img/modeIcons/sz.png'
|
||||
import tcIcon from '../img/modeIcons/tc.png'
|
||||
import rmIcon from '../img/modeIcons/rm.png'
|
||||
import cbIcon from '../img/modeIcons/cb.png'
|
||||
import React, { useEffect, useState, useRef } from "react"
|
||||
import {
|
||||
Loader,
|
||||
Checkbox,
|
||||
Form,
|
||||
Header,
|
||||
List,
|
||||
Image,
|
||||
Divider,
|
||||
Icon,
|
||||
Grid,
|
||||
Input,
|
||||
Button,
|
||||
Label,
|
||||
Segment
|
||||
} from "semantic-ui-react"
|
||||
import { useQuery } from "react-apollo-hooks"
|
||||
import { maplists } from "../../graphql/queries/maplists"
|
||||
import szIcon from "../img/modeIcons/sz.png"
|
||||
import tcIcon from "../img/modeIcons/tc.png"
|
||||
import rmIcon from "../img/modeIcons/rm.png"
|
||||
import cbIcon from "../img/modeIcons/cb.png"
|
||||
|
||||
const MapListGenerator = ({ setMenuSelection }) => {
|
||||
const { data, error, loading } = useQuery(maplists)
|
||||
const [ maps, setMaps ] = useState([])
|
||||
const [ boxValue, setBoxValue ] = useState(0)
|
||||
const [ mapValues, setMapValues ] = useState([])
|
||||
const [ amountToGenerate, setAmountToGenerate ] = useState(12)
|
||||
const [ generatedMaps, setGeneratedMaps ] = useState([])
|
||||
const [ generationType, setGenerationType] = useState('rotate')
|
||||
const [copySuccess, setCopySuccess] = useState('')
|
||||
const [maps, setMaps] = useState([])
|
||||
const [boxValue, setBoxValue] = useState(0)
|
||||
const [mapValues, setMapValues] = useState([])
|
||||
const [amountToGenerate, setAmountToGenerate] = useState(12)
|
||||
const [generatedMaps, setGeneratedMaps] = useState([])
|
||||
const [generationType, setGenerationType] = useState("rotate")
|
||||
const [copySuccess, setCopySuccess] = useState("")
|
||||
const textAreaRef = useRef(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (loading) {
|
||||
return
|
||||
}
|
||||
setMenuSelection('maplists')
|
||||
document.title = 'Maplist Generator - sendou.ink'
|
||||
setMenuSelection("maplists")
|
||||
document.title = "Maplist Generator - sendou.ink"
|
||||
setMaps(data.maplists)
|
||||
|
||||
setMapValues(data.maplists.reduce((acc, cur) => {
|
||||
return (
|
||||
acc.concat({
|
||||
setMapValues(
|
||||
data.maplists.reduce((acc, cur) => {
|
||||
return acc.concat({
|
||||
sz: new Array(cur.sz.length).fill(true),
|
||||
tc: new Array(cur.tc.length).fill(true),
|
||||
rm: new Array(cur.rm.length).fill(true),
|
||||
cb: new Array(cur.cb.length).fill(true),
|
||||
cb: new Array(cur.cb.length).fill(true)
|
||||
})
|
||||
)
|
||||
}, []))
|
||||
|
||||
}, [])
|
||||
)
|
||||
}, [data, loading, setMenuSelection])
|
||||
|
||||
if (loading || maps.length === 0) {
|
||||
return <div style={{"paddingTop": "25px", "paddingBottom": "20000px"}} ><Loader active inline='centered' /></div>
|
||||
return (
|
||||
<div style={{ paddingTop: "25px", paddingBottom: "20000px" }}>
|
||||
<Loader active inline="centered" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
if (error) {
|
||||
return <div style={{"color": "red"}}>{error.message}</div>
|
||||
return <div style={{ color: "red" }}>{error.message}</div>
|
||||
}
|
||||
|
||||
function copyToClipboard(e) {
|
||||
textAreaRef.current.select()
|
||||
document.execCommand('copy')
|
||||
document.execCommand("copy")
|
||||
e.target.focus()
|
||||
setCopySuccess('Copied!')
|
||||
setCopySuccess("Copied!")
|
||||
}
|
||||
|
||||
function shuffle(a) {
|
||||
for (let i = a.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[a[i], a[j]] = [a[j], a[i]];
|
||||
const j = Math.floor(Math.random() * (i + 1))
|
||||
;[a[i], a[j]] = [a[j], a[i]]
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
|
@ -66,13 +83,16 @@ const MapListGenerator = ({ setMenuSelection }) => {
|
|||
const tcMaps = maps[boxValue].tc.filter((m, i) => mapValues[boxValue].tc[i])
|
||||
const rmMaps = maps[boxValue].rm.filter((m, i) => mapValues[boxValue].rm[i])
|
||||
const cbMaps = maps[boxValue].cb.filter((m, i) => mapValues[boxValue].cb[i])
|
||||
if (szMaps.length+tcMaps.length+rmMaps.length+cbMaps.length === 0) {
|
||||
if (szMaps.length + tcMaps.length + rmMaps.length + cbMaps.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
let mapsWithModes = [...szMaps.map(m => `Splat Zones on ${m}`),
|
||||
...tcMaps.map(m => `Tower Control on ${m}`), ...rmMaps.map(m => `Rainmaker on ${m}`),
|
||||
...cbMaps.map(m => `Clam Blitz on ${m}`)]
|
||||
let mapsWithModes = [
|
||||
...szMaps.map(m => `Splat Zones on ${m}`),
|
||||
...tcMaps.map(m => `Tower Control on ${m}`),
|
||||
...rmMaps.map(m => `Rainmaker on ${m}`),
|
||||
...cbMaps.map(m => `Clam Blitz on ${m}`)
|
||||
]
|
||||
const toSetAsState = []
|
||||
let usedMaps = []
|
||||
shuffle(mapsWithModes)
|
||||
|
|
@ -84,7 +104,7 @@ const MapListGenerator = ({ setMenuSelection }) => {
|
|||
usedMaps = []
|
||||
}
|
||||
const modeMap = mapsWithModes.pop()
|
||||
toSetAsState.push(`${toSetAsState.length+1}) ${modeMap}`)
|
||||
toSetAsState.push(`${toSetAsState.length + 1}) ${modeMap}`)
|
||||
usedMaps.push(modeMap)
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +151,7 @@ const MapListGenerator = ({ setMenuSelection }) => {
|
|||
let szRemainder = modes.length + 1
|
||||
if (szEveryOther) {
|
||||
szRemainder = 2
|
||||
shuffle(modes) //not shuffled if sz->tc->cb->rm for host convenience
|
||||
shuffle(modes) //not shuffled if sz->tc->cb->rm for host convenience
|
||||
}
|
||||
|
||||
for (let i = amountToGenerate; i > 0; i--) {
|
||||
|
|
@ -154,16 +174,17 @@ const MapListGenerator = ({ setMenuSelection }) => {
|
|||
usedCb = []
|
||||
}
|
||||
|
||||
if (i % szRemainder === 0 && szMapMode.length !== 0) { //latter check is for if user selected 0 sz maps
|
||||
if (i % szRemainder === 0 && szMapMode.length !== 0) {
|
||||
//latter check is for if user selected 0 sz maps
|
||||
const modeMap = szMapMode.shift()
|
||||
toSetAsState.push(`${toSetAsState.length+1}) ${modeMap}`)
|
||||
toSetAsState.push(`${toSetAsState.length + 1}) ${modeMap}`)
|
||||
usedSz.push(modeMap)
|
||||
continue
|
||||
}
|
||||
|
||||
if (modes[0] === "TOWER CONTROL" && tcMapMode.length !== 0) {
|
||||
const modeMap = tcMapMode.shift()
|
||||
toSetAsState.push(`${toSetAsState.length+1}) ${modeMap}`)
|
||||
toSetAsState.push(`${toSetAsState.length + 1}) ${modeMap}`)
|
||||
usedTc.push(modeMap)
|
||||
modes.push(modes.splice(0, 1)[0]) // move the mode to last
|
||||
continue
|
||||
|
|
@ -171,7 +192,7 @@ const MapListGenerator = ({ setMenuSelection }) => {
|
|||
|
||||
if (modes[0] === "RAINMAKER" && rmMapMode.length !== 0) {
|
||||
const modeMap = rmMapMode.shift()
|
||||
toSetAsState.push(`${toSetAsState.length+1}) ${modeMap}`)
|
||||
toSetAsState.push(`${toSetAsState.length + 1}) ${modeMap}`)
|
||||
usedRm.push(modeMap)
|
||||
modes.push(modes.splice(0, 1)[0])
|
||||
continue
|
||||
|
|
@ -179,7 +200,7 @@ const MapListGenerator = ({ setMenuSelection }) => {
|
|||
|
||||
if (modes[0] === "CLAM BLITZ" && cbMapMode.length !== 0) {
|
||||
const modeMap = cbMapMode.shift()
|
||||
toSetAsState.push(`${toSetAsState.length+1}) ${modeMap}`)
|
||||
toSetAsState.push(`${toSetAsState.length + 1}) ${modeMap}`)
|
||||
usedCb.push(modeMap)
|
||||
modes.push(modes.splice(0, 1)[0])
|
||||
}
|
||||
|
|
@ -189,191 +210,208 @@ const MapListGenerator = ({ setMenuSelection }) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<div style={{"paddingTop": "5px"}}>
|
||||
<Divider horizontal>
|
||||
<Header as='h4'>
|
||||
<Icon name='map' />
|
||||
Choose the map pool to use
|
||||
</Header>
|
||||
</Divider>
|
||||
<Form>
|
||||
{maps.map((m, i) => {
|
||||
return (
|
||||
<Form.Field key={m.name}>
|
||||
<Checkbox
|
||||
radio
|
||||
label={m.name}
|
||||
name='map'
|
||||
checked={i === boxValue}
|
||||
onChange={() => setBoxValue(i)}
|
||||
/>
|
||||
</Form.Field>
|
||||
)
|
||||
})}
|
||||
</Form>
|
||||
<div>
|
||||
<Segment>
|
||||
<div style={{"padding": "5px"}}>
|
||||
<Divider horizontal>
|
||||
<Header as='h4'>
|
||||
<Icon name='checkmark box' />
|
||||
Choose the maps to include
|
||||
<Header as="h4">
|
||||
<Icon name="map" />
|
||||
Choose the map pool to use
|
||||
</Header>
|
||||
</Divider>
|
||||
<Grid relaxed='very' columns={4} stackable>
|
||||
<Grid.Column>
|
||||
<Image src={szIcon} size="tiny" /><br />
|
||||
<List>
|
||||
{maps[boxValue].sz.map((m, i) => {
|
||||
return (
|
||||
<List.Item key={m}>
|
||||
<Checkbox
|
||||
label={m}
|
||||
checked={mapValues[boxValue].sz[i]}
|
||||
onChange={() => {
|
||||
const copy = [...mapValues]
|
||||
copy[boxValue].sz[i] = !copy[boxValue].sz[i]
|
||||
setMapValues(copy)
|
||||
}}
|
||||
/>
|
||||
</List.Item>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Image src={tcIcon} size="tiny" /><br />
|
||||
<List>
|
||||
{maps[boxValue].tc.map((m, i) => {
|
||||
return (
|
||||
<List.Item key={m}>
|
||||
<Checkbox
|
||||
label={m}
|
||||
checked={mapValues[boxValue].tc[i]}
|
||||
onChange={() => {
|
||||
const copy = [...mapValues]
|
||||
copy[boxValue].tc[i] = !copy[boxValue].tc[i]
|
||||
setMapValues(copy)
|
||||
}}
|
||||
/>
|
||||
</List.Item>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Image src={rmIcon} size="tiny" /><br />
|
||||
<List>
|
||||
{maps[boxValue].rm.map((m, i) => {
|
||||
return (
|
||||
<List.Item key={m}>
|
||||
<Checkbox
|
||||
label={m}
|
||||
checked={mapValues[boxValue].rm[i]}
|
||||
onChange={() => {
|
||||
const copy = [...mapValues]
|
||||
copy[boxValue].rm[i] = !copy[boxValue].rm[i]
|
||||
setMapValues(copy)
|
||||
}}
|
||||
/>
|
||||
</List.Item>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Image src={cbIcon} size="tiny" /><br />
|
||||
<List>
|
||||
{maps[boxValue].cb.map((m, i) => {
|
||||
return (
|
||||
<List.Item key={m}>
|
||||
<Checkbox
|
||||
label={m}
|
||||
checked={mapValues[boxValue].cb[i]}
|
||||
onChange={() => {
|
||||
const copy = [...mapValues]
|
||||
copy[boxValue].cb[i] = !copy[boxValue].cb[i]
|
||||
setMapValues(copy)
|
||||
}}
|
||||
/>
|
||||
</List.Item>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
</div>
|
||||
<div style={{"paddingTop": "5px"}}>
|
||||
<Divider horizontal>
|
||||
<Header as='h4'>
|
||||
<Icon name='clipboard list' />
|
||||
Set the final preferences & generate!
|
||||
</Header>
|
||||
</Divider>
|
||||
<Input
|
||||
type='number'
|
||||
placeholder='Choose amount'
|
||||
label='Choose the amount of maps to generate'
|
||||
value={amountToGenerate}
|
||||
onChange={(e) => setAmountToGenerate(e.target.value)}
|
||||
error={amountToGenerate < 1 || amountToGenerate > 100}
|
||||
/>
|
||||
{(amountToGenerate < 1 || amountToGenerate > 100) ? <Label basic color='red' pointing='left'>
|
||||
Amount of maps to generate has to be between 1 and 100
|
||||
</Label> : null}
|
||||
</div>
|
||||
<div style={{"paddingTop": "5px"}}>
|
||||
<Form.Field>
|
||||
<Checkbox
|
||||
radio
|
||||
label="Rotate mode SZ->TC->CB->RM"
|
||||
name='rotateMode'
|
||||
checked={generationType === 'rotate'}
|
||||
onChange={() => setGenerationType('rotate')}
|
||||
/><br/>
|
||||
<Checkbox
|
||||
radio
|
||||
label="SZ every other map"
|
||||
name='szEveryOther'
|
||||
checked={generationType === 'everyOther'}
|
||||
onChange={() => setGenerationType('everyOther')}
|
||||
/><br/>
|
||||
<Checkbox
|
||||
radio
|
||||
label="Total randomness"
|
||||
name='random'
|
||||
checked={generationType === 'random'}
|
||||
onChange={() => setGenerationType('random')}
|
||||
<Form>
|
||||
{maps.map((m, i) => {
|
||||
return (
|
||||
<Form.Field key={m.name}>
|
||||
<Checkbox
|
||||
radio
|
||||
label={m.name}
|
||||
name="map"
|
||||
checked={i === boxValue}
|
||||
onChange={() => setBoxValue(i)}
|
||||
/>
|
||||
</Form.Field>
|
||||
)
|
||||
})}
|
||||
</Form>
|
||||
<div>
|
||||
<Divider horizontal>
|
||||
<Header as="h4">
|
||||
<Icon name="checkmark box" />
|
||||
Choose the maps to include
|
||||
</Header>
|
||||
</Divider>
|
||||
<Grid relaxed="very" columns={4} stackable>
|
||||
<Grid.Column>
|
||||
<Image src={szIcon} size="tiny" />
|
||||
<br />
|
||||
<List>
|
||||
{maps[boxValue].sz.map((m, i) => {
|
||||
return (
|
||||
<List.Item key={m}>
|
||||
<Checkbox
|
||||
label={m}
|
||||
checked={mapValues[boxValue].sz[i]}
|
||||
onChange={() => {
|
||||
const copy = [...mapValues]
|
||||
copy[boxValue].sz[i] = !copy[boxValue].sz[i]
|
||||
setMapValues(copy)
|
||||
}}
|
||||
/>
|
||||
</List.Item>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Image src={tcIcon} size="tiny" />
|
||||
<br />
|
||||
<List>
|
||||
{maps[boxValue].tc.map((m, i) => {
|
||||
return (
|
||||
<List.Item key={m}>
|
||||
<Checkbox
|
||||
label={m}
|
||||
checked={mapValues[boxValue].tc[i]}
|
||||
onChange={() => {
|
||||
const copy = [...mapValues]
|
||||
copy[boxValue].tc[i] = !copy[boxValue].tc[i]
|
||||
setMapValues(copy)
|
||||
}}
|
||||
/>
|
||||
</List.Item>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Image src={rmIcon} size="tiny" />
|
||||
<br />
|
||||
<List>
|
||||
{maps[boxValue].rm.map((m, i) => {
|
||||
return (
|
||||
<List.Item key={m}>
|
||||
<Checkbox
|
||||
label={m}
|
||||
checked={mapValues[boxValue].rm[i]}
|
||||
onChange={() => {
|
||||
const copy = [...mapValues]
|
||||
copy[boxValue].rm[i] = !copy[boxValue].rm[i]
|
||||
setMapValues(copy)
|
||||
}}
|
||||
/>
|
||||
</List.Item>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Image src={cbIcon} size="tiny" />
|
||||
<br />
|
||||
<List>
|
||||
{maps[boxValue].cb.map((m, i) => {
|
||||
return (
|
||||
<List.Item key={m}>
|
||||
<Checkbox
|
||||
label={m}
|
||||
checked={mapValues[boxValue].cb[i]}
|
||||
onChange={() => {
|
||||
const copy = [...mapValues]
|
||||
copy[boxValue].cb[i] = !copy[boxValue].cb[i]
|
||||
setMapValues(copy)
|
||||
}}
|
||||
/>
|
||||
</List.Item>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
</div>
|
||||
<div style={{ paddingTop: "5px" }}>
|
||||
<Divider horizontal>
|
||||
<Header as="h4">
|
||||
<Icon name="clipboard list" />
|
||||
Set the final preferences & generate!
|
||||
</Header>
|
||||
</Divider>
|
||||
<Input
|
||||
type="number"
|
||||
placeholder="Choose amount"
|
||||
label="Choose the amount of maps to generate"
|
||||
value={amountToGenerate}
|
||||
onChange={e => setAmountToGenerate(e.target.value)}
|
||||
error={amountToGenerate < 1 || amountToGenerate > 100}
|
||||
/>
|
||||
</Form.Field>
|
||||
</div>
|
||||
<div style={{"paddingTop": "10px"}}>
|
||||
<Button
|
||||
disabled={amountToGenerate < 1 || amountToGenerate > 100}
|
||||
onClick={() => {generationType === 'random' ? generateRandomMapPool() : generateEvenMapPool(generationType === 'everyOther')}}>Go!
|
||||
</Button>
|
||||
</div>
|
||||
<div style={{"paddingTop": "5px"}}>
|
||||
{generatedMaps.length !== 0 ?
|
||||
<div>
|
||||
<textarea
|
||||
rows={generatedMaps.length + 2}
|
||||
style={{"resize": "none", "width": "300px"}}
|
||||
readOnly
|
||||
value={generatedMaps.join("\n")}
|
||||
ref={textAreaRef}
|
||||
/><br/>
|
||||
{
|
||||
document.queryCommandSupported('copy') &&
|
||||
{amountToGenerate < 1 || amountToGenerate > 100 ? (
|
||||
<Label basic color="red" pointing="left">
|
||||
Amount of maps to generate has to be between 1 and 100
|
||||
</Label>
|
||||
) : null}
|
||||
</div>
|
||||
<div style={{ paddingTop: "5px" }}>
|
||||
<Form.Field>
|
||||
<Checkbox
|
||||
radio
|
||||
label="Rotate mode SZ->TC->CB->RM"
|
||||
name="rotateMode"
|
||||
checked={generationType === "rotate"}
|
||||
onChange={() => setGenerationType("rotate")}
|
||||
/>
|
||||
<br />
|
||||
<Checkbox
|
||||
radio
|
||||
label="SZ every other map"
|
||||
name="szEveryOther"
|
||||
checked={generationType === "everyOther"}
|
||||
onChange={() => setGenerationType("everyOther")}
|
||||
/>
|
||||
<br />
|
||||
<Checkbox
|
||||
radio
|
||||
label="Total randomness"
|
||||
name="random"
|
||||
checked={generationType === "random"}
|
||||
onChange={() => setGenerationType("random")}
|
||||
/>
|
||||
</Form.Field>
|
||||
</div>
|
||||
<div style={{ paddingTop: "10px" }}>
|
||||
<Button
|
||||
disabled={amountToGenerate < 1 || amountToGenerate > 100}
|
||||
onClick={() => {
|
||||
generationType === "random"
|
||||
? generateRandomMapPool()
|
||||
: generateEvenMapPool(generationType === "everyOther")
|
||||
}}
|
||||
>
|
||||
Go!
|
||||
</Button>
|
||||
</div>
|
||||
<div style={{ paddingTop: "5px" }}>
|
||||
{generatedMaps.length !== 0 ? (
|
||||
<div>
|
||||
<textarea
|
||||
rows={generatedMaps.length + 2}
|
||||
style={{ resize: "none", width: "300px" }}
|
||||
readOnly
|
||||
value={generatedMaps.join("\n")}
|
||||
ref={textAreaRef}
|
||||
/>
|
||||
<br />
|
||||
{document.queryCommandSupported("copy") && (
|
||||
<div>
|
||||
<Button onClick={copyToClipboard}>Copy maps to clipboard</Button>
|
||||
<Button onClick={copyToClipboard}>
|
||||
Copy maps to clipboard
|
||||
</Button>
|
||||
{copySuccess}
|
||||
</div>
|
||||
}
|
||||
</div> :
|
||||
null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</Segment>
|
||||
)
|
||||
}
|
||||
|
||||
export default MapListGenerator
|
||||
export default MapListGenerator
|
||||
|
|
|
|||
3
react-ui/src/components/Tools/MapPlanner.js
vendored
|
|
@ -66,13 +66,12 @@ const MapPlanner = ({ setMenuSelection }) => {
|
|||
const [canUndo, setCanUndo] = useState(false)
|
||||
const [canRedo, setCanRedo] = useState(false)
|
||||
const [text, setText] = useState('')
|
||||
const [bg, setBg] = useState(reef)
|
||||
const [bg, setBg] = useState(null)
|
||||
const [uploadError, setUploadError] = useState(null)
|
||||
const [controlledValue, setControlledValue] = useState(defaultValue)
|
||||
|
||||
useEffect(() => {
|
||||
if (!sketch) return
|
||||
sketch.setBackgroundFromDataUrl(bg)
|
||||
setMenuSelection('plans')
|
||||
document.title = 'Planner - sendou.ink'
|
||||
}, [sketch, setMenuSelection, bg])
|
||||
|
|
|
|||
574
react-ui/src/components/Tools/Rotations.js
vendored
|
|
@ -1,39 +1,48 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { useQuery } from 'react-apollo-hooks'
|
||||
import { rotationData } from '../../graphql/queries/rotationData'
|
||||
import { maplists } from '../../graphql/queries/maplists'
|
||||
import { Loader, Segment, Header, Grid, Image, Popup, Button, Checkbox } from 'semantic-ui-react'
|
||||
import React, { useEffect, useState } from "react"
|
||||
import { useQuery } from "react-apollo-hooks"
|
||||
import { rotationData } from "../../graphql/queries/rotationData"
|
||||
import { maplists } from "../../graphql/queries/maplists"
|
||||
import {
|
||||
Loader,
|
||||
Segment,
|
||||
Header,
|
||||
Grid,
|
||||
Image,
|
||||
Popup,
|
||||
Button,
|
||||
Checkbox
|
||||
} from "semantic-ui-react"
|
||||
|
||||
import arowana_mall from '../img/mapIcons/arowana_mall.png'
|
||||
import anchov_games from '../img/mapIcons/ancho-v_games.png'
|
||||
import blackbelly_skatepark from '../img/mapIcons/blackbelly_skatepark.png'
|
||||
import camp_triggerfish from '../img/mapIcons/camp_triggerfish.png'
|
||||
import goby_arena from '../img/mapIcons/goby_arena.png'
|
||||
import humpback_pump_track from '../img/mapIcons/humpback_pump_track.png'
|
||||
import inkblot_art_academy from '../img/mapIcons/inkblot_art_academy.png'
|
||||
import kelp_dome from '../img/mapIcons/kelp_dome.png'
|
||||
import makomart from '../img/mapIcons/makomart.png'
|
||||
import manta_maria from '../img/mapIcons/manta_maria.png'
|
||||
import moray_towers from '../img/mapIcons/moray_towers.png'
|
||||
import musselforge_fitness from '../img/mapIcons/musselforge_fitness.png'
|
||||
import new_albacore_hotel from '../img/mapIcons/new_albacore_hotel.png'
|
||||
import piranha_pit from '../img/mapIcons/piranha_pit.png'
|
||||
import port_mackerel from '../img/mapIcons/port_mackerel.png'
|
||||
import shellendorf_institute from '../img/mapIcons/shellendorf_institute.png'
|
||||
import skipper_pavilion from '../img/mapIcons/skipper_pavilion.png'
|
||||
import snapper_canal from '../img/mapIcons/snapper_canal.png'
|
||||
import starfish_mainstage from '../img/mapIcons/starfish_mainstage.png'
|
||||
import sturgeon_shipyard from '../img/mapIcons/sturgeon_shipyard.png'
|
||||
import the_reef from '../img/mapIcons/the_reef.png'
|
||||
import wahoo_world from '../img/mapIcons/wahoo_world.png'
|
||||
import walleye_warehouse from '../img/mapIcons/walleye_warehouse.png'
|
||||
import rankedIcon from '../img/modeIcons/ranked.png'
|
||||
import regularIcon from '../img/modeIcons/regular.png'
|
||||
import leagueIcon from '../img/modeIcons/league.png'
|
||||
import szIcon from '../img/modeIcons/sz.png'
|
||||
import tcIcon from '../img/modeIcons/tc.png'
|
||||
import rmIcon from '../img/modeIcons/rm.png'
|
||||
import cbIcon from '../img/modeIcons/cb.png'
|
||||
import arowana_mall from "../img/mapIcons/arowana_mall.png"
|
||||
import anchov_games from "../img/mapIcons/ancho-v_games.png"
|
||||
import blackbelly_skatepark from "../img/mapIcons/blackbelly_skatepark.png"
|
||||
import camp_triggerfish from "../img/mapIcons/camp_triggerfish.png"
|
||||
import goby_arena from "../img/mapIcons/goby_arena.png"
|
||||
import humpback_pump_track from "../img/mapIcons/humpback_pump_track.png"
|
||||
import inkblot_art_academy from "../img/mapIcons/inkblot_art_academy.png"
|
||||
import kelp_dome from "../img/mapIcons/kelp_dome.png"
|
||||
import makomart from "../img/mapIcons/makomart.png"
|
||||
import manta_maria from "../img/mapIcons/manta_maria.png"
|
||||
import moray_towers from "../img/mapIcons/moray_towers.png"
|
||||
import musselforge_fitness from "../img/mapIcons/musselforge_fitness.png"
|
||||
import new_albacore_hotel from "../img/mapIcons/new_albacore_hotel.png"
|
||||
import piranha_pit from "../img/mapIcons/piranha_pit.png"
|
||||
import port_mackerel from "../img/mapIcons/port_mackerel.png"
|
||||
import shellendorf_institute from "../img/mapIcons/shellendorf_institute.png"
|
||||
import skipper_pavilion from "../img/mapIcons/skipper_pavilion.png"
|
||||
import snapper_canal from "../img/mapIcons/snapper_canal.png"
|
||||
import starfish_mainstage from "../img/mapIcons/starfish_mainstage.png"
|
||||
import sturgeon_shipyard from "../img/mapIcons/sturgeon_shipyard.png"
|
||||
import the_reef from "../img/mapIcons/the_reef.png"
|
||||
import wahoo_world from "../img/mapIcons/wahoo_world.png"
|
||||
import walleye_warehouse from "../img/mapIcons/walleye_warehouse.png"
|
||||
import rankedIcon from "../img/modeIcons/ranked.png"
|
||||
import regularIcon from "../img/modeIcons/regular.png"
|
||||
import leagueIcon from "../img/modeIcons/league.png"
|
||||
import szIcon from "../img/modeIcons/sz.png"
|
||||
import tcIcon from "../img/modeIcons/tc.png"
|
||||
import rmIcon from "../img/modeIcons/rm.png"
|
||||
import cbIcon from "../img/modeIcons/cb.png"
|
||||
|
||||
const mapIcons = {
|
||||
"Arowana Mall": arowana_mall,
|
||||
|
|
@ -64,31 +73,40 @@ const mapIcons = {
|
|||
const modeIcons = {
|
||||
"Splat Zones": szIcon,
|
||||
"Tower Control": tcIcon,
|
||||
"Rainmaker": rmIcon,
|
||||
Rainmaker: rmIcon,
|
||||
"Clam Blitz": cbIcon
|
||||
}
|
||||
|
||||
const modeShort = {
|
||||
"Splat Zones": "sz",
|
||||
"Tower Control": "tc",
|
||||
"Rainmaker": "rm",
|
||||
Rainmaker: "rm",
|
||||
"Clam Blitz": "cb"
|
||||
}
|
||||
|
||||
const Rotations = ({ setMenuSelection }) => {
|
||||
const { data, error, loading } = useQuery(rotationData)
|
||||
const monthly = useQuery(maplists)
|
||||
const [ rotation, setRotation ] = useState([])
|
||||
const [ preferences, setPreferences ] = useState({sz: {}, tc: {}, rm: {}, cb: {}})
|
||||
const [ show, setShow ] = useState(false)
|
||||
const [ currentTime, setCurrentTime ] = useState(new Date(Math.floor(Date.now() / 1000)))
|
||||
const [rotation, setRotation] = useState([])
|
||||
const [preferences, setPreferences] = useState({
|
||||
sz: {},
|
||||
tc: {},
|
||||
rm: {},
|
||||
cb: {}
|
||||
})
|
||||
const [show, setShow] = useState(false)
|
||||
const [currentTime, setCurrentTime] = useState(
|
||||
new Date(Math.floor(Date.now() / 1000))
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (loading || monthly.loading) {
|
||||
return
|
||||
}
|
||||
|
||||
const rotationPreferencesFromDb = window.localStorage.getItem('rotationPreferences')
|
||||
|
||||
const rotationPreferencesFromDb = window.localStorage.getItem(
|
||||
"rotationPreferences"
|
||||
)
|
||||
if (rotationPreferencesFromDb) {
|
||||
setPreferences(JSON.parse(rotationPreferencesFromDb))
|
||||
}
|
||||
|
|
@ -106,15 +124,24 @@ const Rotations = ({ setMenuSelection }) => {
|
|||
}, [currentTime])
|
||||
|
||||
useEffect(() => {
|
||||
setMenuSelection('rotations')
|
||||
document.title = 'Rotations - sendou.ink'
|
||||
setMenuSelection("rotations")
|
||||
document.title = "Rotations - sendou.ink"
|
||||
}, [setMenuSelection])
|
||||
|
||||
if (loading || monthly.loading || rotation.length === 0) {
|
||||
return <div style={{"paddingTop": "25px", "paddingBottom": "20000px"}} ><Loader active inline='centered' /></div>
|
||||
return (
|
||||
<div style={{ paddingTop: "25px", paddingBottom: "20000px" }}>
|
||||
<Loader active inline="centered" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
if (error || monthly.error) {
|
||||
return <div style={{"color": "red"}}>{error ? error.message : null} {monthly.error? monthly.error.message : null}</div>
|
||||
return (
|
||||
<div style={{ color: "red" }}>
|
||||
{error ? error.message : null}{" "}
|
||||
{monthly.error ? monthly.error.message : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const monthlyMaps = monthly.data.maplists[0]
|
||||
|
|
@ -122,106 +149,121 @@ const Rotations = ({ setMenuSelection }) => {
|
|||
return (
|
||||
<div>
|
||||
<div>
|
||||
<Button icon='cog' onClick={() => setShow(!show)}/>
|
||||
{show ?
|
||||
<div>
|
||||
Uncheck a map in the ranked rotation to mark it as a disliked map.
|
||||
<Grid relaxed columns={4}>
|
||||
<Grid.Column>
|
||||
<b>Splat Zones</b>
|
||||
{monthlyMaps.sz.map(m => {
|
||||
return (
|
||||
<div key={m}>
|
||||
<Checkbox
|
||||
label={m}
|
||||
checked={!preferences.sz[m]}
|
||||
onChange={() => {
|
||||
preferences.sz[m] = !preferences.sz[m]
|
||||
window.localStorage.setItem(
|
||||
'rotationPreferences', JSON.stringify(preferences)
|
||||
)
|
||||
}}
|
||||
/><br/>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<b>Tower Control</b>
|
||||
{monthlyMaps.tc.map(m => {
|
||||
return (
|
||||
<div key={m}>
|
||||
<Checkbox
|
||||
label={m}
|
||||
checked={!preferences.tc[m]}
|
||||
onChange={() => {
|
||||
preferences.tc[m] = !preferences.tc[m]
|
||||
window.localStorage.setItem(
|
||||
'rotationPreferences', JSON.stringify(preferences)
|
||||
)
|
||||
}}
|
||||
/><br/>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<b>Rainmaker</b>
|
||||
{monthlyMaps.rm.map(m => {
|
||||
return (
|
||||
<div key={m}>
|
||||
<Checkbox
|
||||
label={m}
|
||||
checked={!preferences.rm[m]}
|
||||
onChange={() => {
|
||||
preferences.rm[m] = !preferences.rm[m]
|
||||
window.localStorage.setItem(
|
||||
'rotationPreferences', JSON.stringify(preferences)
|
||||
)
|
||||
}}
|
||||
/><br/>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<b>Clam Blitz</b>
|
||||
{monthlyMaps.cb.map(m => {
|
||||
return (
|
||||
<div key={m}>
|
||||
<Checkbox
|
||||
label={m}
|
||||
checked={!preferences.cb[m]}
|
||||
onChange={() => {
|
||||
preferences.cb[m] = !preferences.cb[m]
|
||||
window.localStorage.setItem(
|
||||
'rotationPreferences', JSON.stringify(preferences)
|
||||
)
|
||||
}}
|
||||
/><br/>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
</div>
|
||||
: null}
|
||||
<Button icon="cog" onClick={() => setShow(!show)} />
|
||||
{show ? (
|
||||
<Segment>
|
||||
<div style={{"padding": "5px"}}>
|
||||
Uncheck a map in the ranked rotation to mark it as a disliked map.
|
||||
<Grid relaxed columns={4}>
|
||||
<Grid.Column>
|
||||
<b>Splat Zones</b>
|
||||
{monthlyMaps.sz.map(m => {
|
||||
return (
|
||||
<div key={m}>
|
||||
<Checkbox
|
||||
label={m}
|
||||
checked={!preferences.sz[m]}
|
||||
onChange={() => {
|
||||
preferences.sz[m] = !preferences.sz[m]
|
||||
window.localStorage.setItem(
|
||||
"rotationPreferences",
|
||||
JSON.stringify(preferences)
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<br />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<b>Tower Control</b>
|
||||
{monthlyMaps.tc.map(m => {
|
||||
return (
|
||||
<div key={m}>
|
||||
<Checkbox
|
||||
label={m}
|
||||
checked={!preferences.tc[m]}
|
||||
onChange={() => {
|
||||
preferences.tc[m] = !preferences.tc[m]
|
||||
window.localStorage.setItem(
|
||||
"rotationPreferences",
|
||||
JSON.stringify(preferences)
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<br />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<b>Rainmaker</b>
|
||||
{monthlyMaps.rm.map(m => {
|
||||
return (
|
||||
<div key={m}>
|
||||
<Checkbox
|
||||
label={m}
|
||||
checked={!preferences.rm[m]}
|
||||
onChange={() => {
|
||||
preferences.rm[m] = !preferences.rm[m]
|
||||
window.localStorage.setItem(
|
||||
"rotationPreferences",
|
||||
JSON.stringify(preferences)
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<br />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<b>Clam Blitz</b>
|
||||
{monthlyMaps.cb.map(m => {
|
||||
return (
|
||||
<div key={m}>
|
||||
<Checkbox
|
||||
label={m}
|
||||
checked={!preferences.cb[m]}
|
||||
onChange={() => {
|
||||
preferences.cb[m] = !preferences.cb[m]
|
||||
window.localStorage.setItem(
|
||||
"rotationPreferences",
|
||||
JSON.stringify(preferences)
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<br />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
</div>
|
||||
</Segment>
|
||||
) : null}
|
||||
</div>
|
||||
<div>
|
||||
{rotation.gachi.map((r, i) => { //league maps references like so: rotation.league[i] - turf: rotation.normal[i]
|
||||
{rotation.gachi.map((r, i) => {
|
||||
//league maps references like so: rotation.league[i] - turf: rotation.normal[i]
|
||||
if (r.end_time < currentTime) {
|
||||
return null
|
||||
}
|
||||
const timeUntil = r.start_time - currentTime
|
||||
const hours = Math.floor(timeUntil / 3600)
|
||||
const minutes = Math.floor((timeUntil % 3600) / 60)
|
||||
const seconds = timeUntil % 3600 % 60
|
||||
let header = 'Current'
|
||||
const seconds = (timeUntil % 3600) % 60
|
||||
let header = "Current"
|
||||
if (hours >= 2) {
|
||||
if (minutes === 1) {
|
||||
header = `In ${hours} hours ${minutes} minute (${new Date(r.start_time * 1000).toLocaleString('en-GB')})`
|
||||
header = `In ${hours} hours ${minutes} minute (${new Date(
|
||||
r.start_time * 1000
|
||||
).toLocaleString("en-GB")})`
|
||||
} else {
|
||||
header = `In ${hours} hours ${minutes} minutes (${new Date(r.start_time * 1000).toLocaleString('en-GB')})`
|
||||
header = `In ${hours} hours ${minutes} minutes (${new Date(
|
||||
r.start_time * 1000
|
||||
).toLocaleString("en-GB")})`
|
||||
}
|
||||
} else if (hours > 0) {
|
||||
if (minutes === 1) {
|
||||
|
|
@ -237,97 +279,175 @@ const Rotations = ({ setMenuSelection }) => {
|
|||
}
|
||||
}
|
||||
return (
|
||||
<div key={r.start_time} style={{"paddingTop": "25px"}}>
|
||||
<Header size='small' disabled={preferences[modeShort[r.rule.name]][r.stage_a.name] && preferences[modeShort[r.rule.name]][r.stage_b.name]}>{header}</Header>
|
||||
<Segment disabled={preferences[modeShort[r.rule.name]][r.stage_a.name] && preferences[modeShort[r.rule.name]][r.stage_b.name]} raised>
|
||||
<Grid columns={3} stackable>
|
||||
<Grid.Row>
|
||||
<Grid.Column>
|
||||
<Header textAlign='center'>
|
||||
<Image src={leagueIcon} style={{"paddingBottom": "10px"}}/> LEAGUE
|
||||
<Header.Subheader style={{"paddingTop": "10px"}}><Image size="mini" src={modeIcons[rotation.league[i].rule.name]} avatar/><b>{rotation.league[i].rule.name}</b></Header.Subheader>
|
||||
</Header>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Header textAlign='center'>
|
||||
<Image src={rankedIcon} style={{"paddingBottom": "10px"}}/> RANKED
|
||||
<Header.Subheader style={{"paddingTop": "10px"}}><Image size="mini" src={modeIcons[r.rule.name]} avatar/><b>{r.rule.name}</b></Header.Subheader>
|
||||
</Header>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Header textAlign='center'>
|
||||
<Image src={regularIcon} style={{"paddingBottom": "10px"}}/>REGULAR
|
||||
<Header.Subheader style={{"paddingTop": "10px"}}></Header.Subheader> {/*this is needed for formatting reasons.*/}
|
||||
</Header>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
<Grid.Row>
|
||||
<Grid.Column>
|
||||
<div style={{display: 'flex', justifyContent:'center', alignItems:'center'}}>
|
||||
<Popup
|
||||
trigger={<Image
|
||||
src={mapIcons[rotation.league[i].stage_a.name]}
|
||||
rounded
|
||||
/>}
|
||||
content={rotation.league[i].stage_a.name}
|
||||
basic
|
||||
/>
|
||||
<Popup
|
||||
trigger={<Image
|
||||
src={mapIcons[rotation.league[i].stage_b.name]}
|
||||
rounded
|
||||
/>}
|
||||
content={rotation.league[i].stage_b.name}
|
||||
basic
|
||||
/>
|
||||
</div>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<div style={{display: 'flex', justifyContent:'center', alignItems:'center'}}>
|
||||
<Popup
|
||||
trigger={<Image
|
||||
src={mapIcons[r.stage_a.name]}
|
||||
rounded
|
||||
disabled={preferences[modeShort[r.rule.name]][r.stage_a.name]}
|
||||
/>}
|
||||
content={r.stage_a.name}
|
||||
basic
|
||||
/>
|
||||
<Popup
|
||||
trigger={<Image
|
||||
src={mapIcons[r.stage_b.name]}
|
||||
rounded
|
||||
disabled={preferences[modeShort[r.rule.name]][r.stage_b.name]}
|
||||
/>}
|
||||
content={r.stage_b.name}
|
||||
basic
|
||||
/>
|
||||
</div>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<div style={{display: 'flex', justifyContent:'center', alignItems:'center'}}>
|
||||
<Popup
|
||||
trigger={<Image
|
||||
src={mapIcons[rotation.regular[i].stage_a.name]}
|
||||
rounded
|
||||
/>}
|
||||
content={rotation.regular[i].stage_a.name}
|
||||
basic
|
||||
/>
|
||||
<Popup
|
||||
trigger={<Image
|
||||
src={mapIcons[rotation.regular[i].stage_b.name]}
|
||||
rounded
|
||||
/>}
|
||||
content={rotation.regular[i].stage_b.name}
|
||||
basic
|
||||
/>
|
||||
</div>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
<div key={r.start_time} style={{ paddingTop: "25px" }}>
|
||||
<Header
|
||||
size="small"
|
||||
disabled={
|
||||
preferences[modeShort[r.rule.name]][r.stage_a.name] &&
|
||||
preferences[modeShort[r.rule.name]][r.stage_b.name]
|
||||
}
|
||||
>
|
||||
{header}
|
||||
</Header>
|
||||
<Segment
|
||||
disabled={
|
||||
preferences[modeShort[r.rule.name]][r.stage_a.name] &&
|
||||
preferences[modeShort[r.rule.name]][r.stage_b.name]
|
||||
}
|
||||
raised
|
||||
>
|
||||
<Grid columns={3} stackable>
|
||||
<Grid.Row>
|
||||
<Grid.Column>
|
||||
<Header textAlign="center">
|
||||
<Image
|
||||
src={leagueIcon}
|
||||
style={{ paddingBottom: "10px" }}
|
||||
/>{" "}
|
||||
LEAGUE
|
||||
<Header.Subheader style={{ paddingTop: "10px" }}>
|
||||
<Image
|
||||
size="mini"
|
||||
src={modeIcons[rotation.league[i].rule.name]}
|
||||
avatar
|
||||
/>
|
||||
<b>{rotation.league[i].rule.name}</b>
|
||||
</Header.Subheader>
|
||||
</Header>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Header textAlign="center">
|
||||
<Image
|
||||
src={rankedIcon}
|
||||
style={{ paddingBottom: "10px" }}
|
||||
/>{" "}
|
||||
RANKED
|
||||
<Header.Subheader style={{ paddingTop: "10px" }}>
|
||||
<Image
|
||||
size="mini"
|
||||
src={modeIcons[r.rule.name]}
|
||||
avatar
|
||||
/>
|
||||
<b>{r.rule.name}</b>
|
||||
</Header.Subheader>
|
||||
</Header>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Header textAlign="center">
|
||||
<Image
|
||||
src={regularIcon}
|
||||
style={{ paddingBottom: "10px" }}
|
||||
/>
|
||||
REGULAR
|
||||
<Header.Subheader style={{ paddingTop: "10px" }} />{" "}
|
||||
{/*this is needed for formatting reasons.*/}
|
||||
</Header>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
<Grid.Row>
|
||||
<Grid.Column>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Popup
|
||||
trigger={
|
||||
<Image
|
||||
src={mapIcons[rotation.league[i].stage_a.name]}
|
||||
rounded
|
||||
/>
|
||||
}
|
||||
content={rotation.league[i].stage_a.name}
|
||||
basic
|
||||
/>
|
||||
<Popup
|
||||
trigger={
|
||||
<Image
|
||||
src={mapIcons[rotation.league[i].stage_b.name]}
|
||||
rounded
|
||||
/>
|
||||
}
|
||||
content={rotation.league[i].stage_b.name}
|
||||
basic
|
||||
/>
|
||||
</div>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Popup
|
||||
trigger={
|
||||
<Image
|
||||
src={mapIcons[r.stage_a.name]}
|
||||
rounded
|
||||
disabled={
|
||||
preferences[modeShort[r.rule.name]][
|
||||
r.stage_a.name
|
||||
]
|
||||
}
|
||||
/>
|
||||
}
|
||||
content={r.stage_a.name}
|
||||
basic
|
||||
/>
|
||||
<Popup
|
||||
trigger={
|
||||
<Image
|
||||
src={mapIcons[r.stage_b.name]}
|
||||
rounded
|
||||
disabled={
|
||||
preferences[modeShort[r.rule.name]][
|
||||
r.stage_b.name
|
||||
]
|
||||
}
|
||||
/>
|
||||
}
|
||||
content={r.stage_b.name}
|
||||
basic
|
||||
/>
|
||||
</div>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Popup
|
||||
trigger={
|
||||
<Image
|
||||
src={mapIcons[rotation.regular[i].stage_a.name]}
|
||||
rounded
|
||||
/>
|
||||
}
|
||||
content={rotation.regular[i].stage_a.name}
|
||||
basic
|
||||
/>
|
||||
<Popup
|
||||
trigger={
|
||||
<Image
|
||||
src={mapIcons[rotation.regular[i].stage_b.name]}
|
||||
rounded
|
||||
/>
|
||||
}
|
||||
content={rotation.regular[i].stage_b.name}
|
||||
basic
|
||||
/>
|
||||
</div>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
</Segment>
|
||||
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
|
|
@ -336,4 +456,4 @@ const Rotations = ({ setMenuSelection }) => {
|
|||
)
|
||||
}
|
||||
|
||||
export default Rotations
|
||||
export default Rotations
|
||||
|
|
|
|||
149
react-ui/src/components/Tools/Tournament.js
vendored
|
|
@ -1,149 +0,0 @@
|
|||
import React, { useState } from 'react'
|
||||
import { Segment, Header, Divider, Popup, Flag, Image, Button, Table } from 'semantic-ui-react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import weaponDict from '../../utils/english_internal.json'
|
||||
import szIcon from '../img/modeIcons/sz.png'
|
||||
import tcIcon from '../img/modeIcons/tc.png'
|
||||
import rmIcon from '../img/modeIcons/rm.png'
|
||||
import cbIcon from '../img/modeIcons/cb.png'
|
||||
|
||||
const Tournament = ({ tournament }) => {
|
||||
const [expanded, setExpanded] = useState(false)
|
||||
const t = tournament
|
||||
let date = null
|
||||
let day = null
|
||||
let month = null
|
||||
let year = null
|
||||
let alphaCount = 0
|
||||
let bravoCount = 0
|
||||
|
||||
const modeIcons = {
|
||||
"Splat Zones": szIcon,
|
||||
"Tower Control": tcIcon,
|
||||
"Rainmaker": rmIcon,
|
||||
"Clam Blitz": cbIcon
|
||||
}
|
||||
|
||||
if (t.timestamp) {
|
||||
const monthNames = ["January", "February", "March", "April", "May", "June",
|
||||
"July", "August", "September", "October", "November", "December"
|
||||
]
|
||||
date = new Date(t.timestamp * 1000)
|
||||
day = date.getDate()
|
||||
month = monthNames[date.getMonth()]
|
||||
year = date.getFullYear()
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Segment raised compact padded>
|
||||
<Header>
|
||||
{t.name}
|
||||
{t.japanese ? <><br/>{<Flag name='jp'/>}</> : null}
|
||||
<Header.Subheader>{t.timestamp ? <>{`${day} ${month} ${year}`}</> : null}{t.patch ? <> | Patch {t.patch}</>: null}</Header.Subheader>
|
||||
<Header.Subheader>
|
||||
{t.bracket ? <a href={t.bracket}>Bracket</a> : null}
|
||||
{t.vod ? <> | <a href={t.vod}>VoD</a></> : null}<br />
|
||||
</Header.Subheader>
|
||||
<Header.Subheader>{t.team_count ? <>{t.team_count} teams</> : null}</Header.Subheader>
|
||||
</Header>
|
||||
<Divider />
|
||||
<b style={{'padding': '3px'}}>{t.alpha_team_name}</b><br/>
|
||||
{t.alpha_team_players.map((p, i) => {
|
||||
if (t.alpha_team[i]) return <span style={{"padding": "3px"}}><Link to={`/xsearch/p/${t.alpha_team[i]}`}>{p}</Link></span>
|
||||
return (
|
||||
<span style={{"padding": "3px"}}>{p}</span>
|
||||
)
|
||||
})}<br/>
|
||||
<span style={{'padding': '3px'}}>vs.</span><br/>
|
||||
<b style={{'padding': '3px'}}>{t.bravo_team_name}</b><br/>
|
||||
{t.bravo_team_players.map((p, i) => {
|
||||
if (t.bravo_team[i]) return <span style={{"padding": "3px"}}><Link to={`/xsearch/p/${t.bravo_team[i]}`}>{p}</Link></span>
|
||||
return (
|
||||
<span style={{"padding": "3px"}}>{p}</span>
|
||||
)
|
||||
})}
|
||||
<div style={{'paddingTop': '3px'}}>
|
||||
{t.weapons.map((w, i) => {
|
||||
return (
|
||||
<span key={w}>
|
||||
<Popup trigger={
|
||||
<Image inline src={process.env.PUBLIC_URL + `/wpnSmall/Wst_${weaponDict[w]}.png`}></Image>
|
||||
}>
|
||||
{w}
|
||||
</Popup>
|
||||
{i % 10 === 0 && i !== 0 ? <br/> : null}
|
||||
</span>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<div style={{'paddingTop': '10px'}}>
|
||||
<Button onClick={() => setExpanded(!expanded)}>
|
||||
{expanded ? 'Hide battles' : 'Show battles'}
|
||||
</Button>
|
||||
</div>
|
||||
{expanded ?
|
||||
<div style={{"paddingTop": "10px"}}>
|
||||
<Table basic='very' celled collapsing>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>Mode</Table.HeaderCell>
|
||||
<Table.HeaderCell>Map</Table.HeaderCell>
|
||||
<Table.HeaderCell>{t.alpha_team_name}<br/>{t.bravo_team_name}</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{t.rounds.map(r => {
|
||||
if (r.winner === 'ALPHA') alphaCount++
|
||||
if (r.winner === 'BRAVO') bravoCount++
|
||||
return (
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Image size="mini" src={modeIcons[r.mode]} />
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
{r.map}
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
{r.alpha_weapons.map((w, i) => {
|
||||
return (
|
||||
<Popup trigger={
|
||||
<Image
|
||||
style={{"maxWidth": "100px", "height": "auto", "width": "auto"}}
|
||||
inline
|
||||
src={process.env.PUBLIC_URL + `/wpnSmall/Wst_${weaponDict[w]}.png`} />}>
|
||||
{t.alpha_team_players[i]}
|
||||
</Popup>
|
||||
)
|
||||
})} {r.winner === 'ALPHA' ? '🏆' : null}<br/>
|
||||
{r.bravo_weapons.map((w, i) => {
|
||||
return (
|
||||
<Popup trigger={
|
||||
<Image
|
||||
style={{"maxWidth": "100px", "height": "auto", "width": "auto"}}
|
||||
inline
|
||||
src={process.env.PUBLIC_URL + `/wpnSmall/Wst_${weaponDict[w]}.png`} />}>
|
||||
{t.bravo_team_players[i]}
|
||||
</Popup>
|
||||
)
|
||||
})} {r.winner === 'BRAVO' ? '🏆' : null}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)
|
||||
})}
|
||||
<Table.Row>
|
||||
<Table.Cell></Table.Cell>
|
||||
<Table.Cell>
|
||||
{t.alpha_team_name} {alphaCount} - {bravoCount} {t.bravo_team_name}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Body>
|
||||
</Table>
|
||||
</div>
|
||||
: null}
|
||||
</Segment>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Tournament
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react'
|
||||
import { Table, Icon, Popup } from 'semantic-ui-react'
|
||||
import { Table, Icon, Popup, Segment } from 'semantic-ui-react'
|
||||
import { useQuery } from 'react-apollo-hooks'
|
||||
import { Loader } from 'semantic-ui-react'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
|
@ -20,40 +20,44 @@ const FlexLeaderboard = ({ setActiveItem }) => {
|
|||
const leaderboard = result.data['topFlex']
|
||||
|
||||
return (
|
||||
<Table style={{"paddingTop": "5px", "paddingBottom": "5px"}} basic='very'>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell></Table.HeaderCell>
|
||||
<Table.HeaderCell>Name</Table.HeaderCell>
|
||||
<Table.HeaderCell>
|
||||
Flex Power
|
||||
<Popup
|
||||
trigger={<Icon name='question circle'/>}
|
||||
content="Flex Power is the amount of unique weapons the player has reached top 500 with. Different kits count as unique weapons but reskins (e.g. Tentatek & Octoshot) don't."
|
||||
position='bottom center'
|
||||
/>
|
||||
</Table.HeaderCell>
|
||||
<Table.HeaderCell>Total Power</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Segment>
|
||||
<div style={{"padding": "5px"}}>
|
||||
<Table basic='very'>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell></Table.HeaderCell>
|
||||
<Table.HeaderCell>Name</Table.HeaderCell>
|
||||
<Table.HeaderCell>
|
||||
Flex Power
|
||||
<Popup
|
||||
trigger={<Icon name='question circle'/>}
|
||||
content="Flex Power is the amount of unique weapons the player has reached top 500 with. Different kits count as unique weapons but reskins (e.g. Tentatek & Octoshot) don't."
|
||||
position='bottom center'
|
||||
/>
|
||||
</Table.HeaderCell>
|
||||
<Table.HeaderCell>Total Power</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
|
||||
<Table.Body>
|
||||
{leaderboard.map((player, index) =>
|
||||
<Table.Row key={player.id}>
|
||||
<Table.Cell>{index + 1}</Table.Cell>
|
||||
<Table.Cell><Link to={`/xsearch/p/${player.unique_id}`} style={{"color": "black"}}><u>{player.alias ? player.alias : player.name}</u></Link>
|
||||
{player.twitter ?
|
||||
<a href={`https://twitter.com/${player.twitter}`}><Icon style={{"paddingLeft": "5px"}} name="twitter"/></a>
|
||||
: null}
|
||||
</Table.Cell>
|
||||
<Table.Cell>{player.weaponsCount}</Table.Cell>
|
||||
<Table.Cell>
|
||||
{player.topTotalScore}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
<Table.Body>
|
||||
{leaderboard.map((player, index) =>
|
||||
<Table.Row key={player.id}>
|
||||
<Table.Cell>{index + 1}</Table.Cell>
|
||||
<Table.Cell><Link to={`/xsearch/p/${player.unique_id}`} style={{"color": "black"}}><u>{player.alias ? player.alias : player.name}</u></Link>
|
||||
{player.twitter ?
|
||||
<a href={`https://twitter.com/${player.twitter}`}><Icon style={{"paddingLeft": "5px"}} name="twitter"/></a>
|
||||
: null}
|
||||
</Table.Cell>
|
||||
<Table.Cell>{player.weaponsCount}</Table.Cell>
|
||||
<Table.Cell>
|
||||
{player.topTotalScore}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
</div>
|
||||
</Segment>
|
||||
)
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react'
|
||||
import { Table, Icon, Popup } from 'semantic-ui-react'
|
||||
import { Table, Icon, Popup, Segment } from 'semantic-ui-react'
|
||||
import { useQuery } from 'react-apollo-hooks'
|
||||
import { Loader } from 'semantic-ui-react'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
|
@ -20,40 +20,44 @@ const WeaponLeaderboard = ({ query, queryName, scoreField, weaponsField, setActi
|
|||
const leaderboard = result.data[queryName]
|
||||
|
||||
return (
|
||||
<Table style={{"paddingTop": "5px", "paddingBottom": "5px"}} basic='very'>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell></Table.HeaderCell>
|
||||
<Table.HeaderCell>Name</Table.HeaderCell>
|
||||
<Table.HeaderCell>
|
||||
{weaponsField.substring(3)} Power
|
||||
<Popup
|
||||
trigger={<Icon name='question circle'/>}
|
||||
content='Power is the average of the top 4 best X powers. Hover over the weapon to receive information about that placement.'
|
||||
position='bottom center'
|
||||
/>
|
||||
</Table.HeaderCell>
|
||||
<Table.HeaderCell>Weapons</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Segment>
|
||||
<div style={{"padding": "5px"}}>
|
||||
<Table basic='very'>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell></Table.HeaderCell>
|
||||
<Table.HeaderCell>Name</Table.HeaderCell>
|
||||
<Table.HeaderCell>
|
||||
{weaponsField.substring(3)} Power
|
||||
<Popup
|
||||
trigger={<Icon name='question circle'/>}
|
||||
content='Power is the average of the top 4 best X powers. Hover over the weapon to receive information about that placement.'
|
||||
position='bottom center'
|
||||
/>
|
||||
</Table.HeaderCell>
|
||||
<Table.HeaderCell>Weapons</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
|
||||
<Table.Body>
|
||||
{leaderboard.map((player, index) =>
|
||||
<Table.Row key={player.id}>
|
||||
<Table.Cell>{index + 1}</Table.Cell>
|
||||
<Table.Cell><Link to={`/xsearch/p/${player.unique_id}`} style={{"color": "black"}}><u>{player.alias ? player.alias : player.name}</u></Link>
|
||||
{player.twitter ?
|
||||
<a href={`https://twitter.com/${player.twitter}`}><Icon style={{"paddingLeft": "5px"}} name="twitter"/></a>
|
||||
: null}
|
||||
</Table.Cell>
|
||||
<Table.Cell>{player[scoreField]}</Table.Cell>
|
||||
<Table.Cell>
|
||||
<FourWeapons weapons={player[weaponsField]} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
<Table.Body>
|
||||
{leaderboard.map((player, index) =>
|
||||
<Table.Row key={player.id}>
|
||||
<Table.Cell>{index + 1}</Table.Cell>
|
||||
<Table.Cell><Link to={`/xsearch/p/${player.unique_id}`} style={{"color": "black"}}><u>{player.alias ? player.alias : player.name}</u></Link>
|
||||
{player.twitter ?
|
||||
<a href={`https://twitter.com/${player.twitter}`}><Icon style={{"paddingLeft": "5px"}} name="twitter"/></a>
|
||||
: null}
|
||||
</Table.Cell>
|
||||
<Table.Cell>{player[scoreField]}</Table.Cell>
|
||||
<Table.Cell>
|
||||
<FourWeapons weapons={player[weaponsField]} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
</div>
|
||||
</Segment>
|
||||
)
|
||||
|
||||
}
|
||||
|
|
|
|||
231
react-ui/src/components/XSearch/InfoPlayer.js
vendored
|
|
@ -1,18 +1,20 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { useQuery } from 'react-apollo-hooks'
|
||||
import { Loader, Header, Image, Icon, List } from 'semantic-ui-react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import React, { useEffect, useState } from "react"
|
||||
import { useQuery } from "react-apollo-hooks"
|
||||
import { Loader, Header, Image, Icon, List, Segment } from "semantic-ui-react"
|
||||
import { Link } from "react-router-dom"
|
||||
|
||||
import { playerInfo } from '../../graphql/queries/playerInfo'
|
||||
import TopPlacementTable from './TopPlacementsTable'
|
||||
import WpnPlayedTable from './WpnPlayedTable'
|
||||
import MonthsTable from './MonthsTable'
|
||||
import { playerInfo } from "../../graphql/queries/playerInfo"
|
||||
import TopPlacementTable from "./TopPlacementsTable"
|
||||
import WpnPlayedTable from "./WpnPlayedTable"
|
||||
import MonthsTable from "./MonthsTable"
|
||||
|
||||
const InfoPlayer = ({ uid, setMenuSelection, twitter }) => {
|
||||
let searchVariables = {}
|
||||
if (uid) searchVariables = { uid }
|
||||
if (twitter) searchVariables = { twitter }
|
||||
const { data, error, loading } = useQuery(playerInfo, {variables: searchVariables})
|
||||
const { data, error, loading } = useQuery(playerInfo, {
|
||||
variables: searchVariables
|
||||
})
|
||||
const [top, setTop] = useState([])
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -20,8 +22,9 @@ const InfoPlayer = ({ uid, setMenuSelection, twitter }) => {
|
|||
return
|
||||
}
|
||||
|
||||
if (setMenuSelection) { //if we're on /xsearch
|
||||
setMenuSelection('search')
|
||||
if (setMenuSelection) {
|
||||
//if we're on /xsearch
|
||||
setMenuSelection("search")
|
||||
}
|
||||
if (data.playerInfo) {
|
||||
const placements = data.playerInfo.placements
|
||||
|
|
@ -29,84 +32,178 @@ const InfoPlayer = ({ uid, setMenuSelection, twitter }) => {
|
|||
//reducing placements to top sz, tc etc. rank and x power
|
||||
const tops = ["", "szTop", "tcTop", "rmTop", "cbTop"]
|
||||
const exs = ["", "szX", "tcX", "rmX", "cbX"]
|
||||
setTop(placements.reduce((acc, cur) => {
|
||||
const topKey = tops[cur.mode]
|
||||
const xKey = exs[cur.mode]
|
||||
if (!acc[xKey]) {
|
||||
acc[xKey] = cur
|
||||
acc[topKey] = cur
|
||||
return acc
|
||||
}
|
||||
if (acc[xKey].x_power < cur.x_power) {
|
||||
acc[xKey] = cur
|
||||
}
|
||||
if (acc[topKey].rank > cur.rank) {
|
||||
acc[topKey] = cur
|
||||
}
|
||||
setTop(
|
||||
placements.reduce(
|
||||
(acc, cur) => {
|
||||
const topKey = tops[cur.mode]
|
||||
const xKey = exs[cur.mode]
|
||||
if (!acc[xKey]) {
|
||||
acc[xKey] = cur
|
||||
acc[topKey] = cur
|
||||
return acc
|
||||
}
|
||||
if (acc[xKey].x_power < cur.x_power) {
|
||||
acc[xKey] = cur
|
||||
}
|
||||
if (acc[topKey].rank > cur.rank) {
|
||||
acc[topKey] = cur
|
||||
}
|
||||
|
||||
return acc
|
||||
}, {
|
||||
szX: null, szTop: null,
|
||||
tcX: null, tcTop: null,
|
||||
rmX: null, rmTop: null,
|
||||
cbX: null, cbTop: null
|
||||
}))
|
||||
return acc
|
||||
},
|
||||
{
|
||||
szX: null,
|
||||
szTop: null,
|
||||
tcX: null,
|
||||
tcTop: null,
|
||||
rmX: null,
|
||||
rmTop: null,
|
||||
cbX: null,
|
||||
cbTop: null
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}, [data, loading, setMenuSelection])
|
||||
|
||||
const addXRankHelp = (
|
||||
<div>
|
||||
This user has no X Rank profile set up. If you are the owner of this user page here is how you can set it up:
|
||||
<div style={{'paddingTop': "5px"}}>
|
||||
<List ordered>
|
||||
<List.Item>Finish an X rank season in the Top 500 in at least one mode.</List.Item>
|
||||
<List.Item>Send your Twitter handle to Sendou via DM.</List.Item>
|
||||
<List.Item>Add your Twitter account to your profile on Discord, verify it and make sure it's set to appear publicly.</List.Item>
|
||||
<List.Item>Log in to sendou.ink</List.Item>
|
||||
</List>
|
||||
</div>
|
||||
This user has no X Rank profile set up. If you are the owner of this user
|
||||
page here is how you can set it up:
|
||||
<div style={{ paddingTop: "5px" }}>
|
||||
<List ordered>
|
||||
<List.Item>
|
||||
Finish an X rank season in the Top 500 in at least one mode.
|
||||
</List.Item>
|
||||
<List.Item>Send your Twitter handle to Sendou via DM.</List.Item>
|
||||
<List.Item>
|
||||
Add your Twitter account to your profile on Discord, verify it and
|
||||
make sure it's set to appear publicly.
|
||||
</List.Item>
|
||||
<List.Item>Log in to sendou.ink</List.Item>
|
||||
</List>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
if (!uid && !twitter) return addXRankHelp
|
||||
|
||||
if (loading) {
|
||||
return <div style={{"paddingTop": "25px", "paddingBottom": "20000px"}} ><Loader active inline='centered' /></div>
|
||||
return (
|
||||
<div style={{ paddingTop: "25px", paddingBottom: "20000px" }}>
|
||||
<Loader active inline="centered" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
if (error) {
|
||||
if (error.message === 'GraphQL error: player not found') {
|
||||
if (error.message === "GraphQL error: player not found") {
|
||||
return addXRankHelp
|
||||
}
|
||||
return <div style={{"color": "red"}}>{error.message}</div>
|
||||
return <div style={{ color: "red" }}>{error.message}</div>
|
||||
}
|
||||
const playerData = data.playerInfo.player
|
||||
|
||||
return (
|
||||
<div style={{"paddingTop": "20px"}}>
|
||||
{setMenuSelection ?
|
||||
<Header as='h2'>
|
||||
{playerData.twitter ? <Image circular src={`https://avatars.io/twitter/${playerData.twitter}`} /> : null} {playerData.alias ? playerData.alias : playerData.name}
|
||||
{playerData.twitter ? <a href={`https://twitter.com/${playerData.twitter}`}><Icon style={{"paddingLeft": "5px"}} size='small' name="twitter"/></a> : null}
|
||||
<div style={{ paddingTop: "20px" }}>
|
||||
{setMenuSelection ? (
|
||||
<Header as="h2">
|
||||
{playerData.twitter ? (
|
||||
<Image
|
||||
circular
|
||||
src={`https://avatars.io/twitter/${playerData.twitter}`}
|
||||
/>
|
||||
) : null}{" "}
|
||||
{playerData.alias ? playerData.alias : playerData.name}
|
||||
{playerData.twitter ? (
|
||||
<a href={`https://twitter.com/${playerData.twitter}`}>
|
||||
<Icon
|
||||
style={{ paddingLeft: "5px" }}
|
||||
size="small"
|
||||
name="twitter"
|
||||
/>
|
||||
</a>
|
||||
) : null}
|
||||
</Header>
|
||||
: null}
|
||||
{(setMenuSelection && playerData.discord_id) ? <><Link to={`/u/${playerData.discord_id}`}>User page</Link><br/></> : null}
|
||||
{playerData.topTotalScore ? <><i>Total Power: {playerData.topTotalScore}</i><br /></> : null}
|
||||
{playerData.topShooterScore ? <><i>Shooter Power: {playerData.topShooterScore}</i><br /></> : null}
|
||||
{playerData.topBlasterScore ? <><i>Blaster Power: {playerData.topBlasterScore}</i><br /></> : null}
|
||||
{playerData.topRollerScore ? <><i>Roller Power: {playerData.topRollerScore}</i><br /></> : null}
|
||||
{playerData.topChargerScore ? <><i>Charger Power: {playerData.topChargerScore}</i><br /></> : null}
|
||||
{playerData.topSlosherScore ? <><i>Slosher Power: {playerData.topSlosherScore}</i><br /></> : null}
|
||||
{playerData.topSplatlingScore ? <><i>Splatling Power: {playerData.topSplatlingScore}</i><br /></> : null}
|
||||
{playerData.topDualiesScore ? <><i>Dualies Power: {playerData.topDualiesScore}</i><br /></> : null}
|
||||
{playerData.topBrellaScore ? <><i>Brella Power: {playerData.topBrellaScore}</i><br /></> : null}
|
||||
<TopPlacementTable top={top} />
|
||||
<Header dividing style={{"paddingTop": "5px"}}>All Top 500 placements</Header>
|
||||
<MonthsTable placements={data.playerInfo.placements} />
|
||||
<Header dividing style={{"paddingTop": "5px"}}>Weapons reached Top 500 with</Header>
|
||||
<WpnPlayedTable weapons={playerData.weapons} />
|
||||
) : null}
|
||||
{setMenuSelection && playerData.discord_id ? (
|
||||
<>
|
||||
<Link to={`/u/${playerData.discord_id}`}>User page</Link>
|
||||
<br />
|
||||
</>
|
||||
) : null}
|
||||
{playerData.topTotalScore ? (
|
||||
<>
|
||||
<i>Total Power: {playerData.topTotalScore}</i>
|
||||
<br />
|
||||
</>
|
||||
) : null}
|
||||
{playerData.topShooterScore ? (
|
||||
<>
|
||||
<i>Shooter Power: {playerData.topShooterScore}</i>
|
||||
<br />
|
||||
</>
|
||||
) : null}
|
||||
{playerData.topBlasterScore ? (
|
||||
<>
|
||||
<i>Blaster Power: {playerData.topBlasterScore}</i>
|
||||
<br />
|
||||
</>
|
||||
) : null}
|
||||
{playerData.topRollerScore ? (
|
||||
<>
|
||||
<i>Roller Power: {playerData.topRollerScore}</i>
|
||||
<br />
|
||||
</>
|
||||
) : null}
|
||||
{playerData.topChargerScore ? (
|
||||
<>
|
||||
<i>Charger Power: {playerData.topChargerScore}</i>
|
||||
<br />
|
||||
</>
|
||||
) : null}
|
||||
{playerData.topSlosherScore ? (
|
||||
<>
|
||||
<i>Slosher Power: {playerData.topSlosherScore}</i>
|
||||
<br />
|
||||
</>
|
||||
) : null}
|
||||
{playerData.topSplatlingScore ? (
|
||||
<>
|
||||
<i>Splatling Power: {playerData.topSplatlingScore}</i>
|
||||
<br />
|
||||
</>
|
||||
) : null}
|
||||
{playerData.topDualiesScore ? (
|
||||
<>
|
||||
<i>Dualies Power: {playerData.topDualiesScore}</i>
|
||||
<br />
|
||||
</>
|
||||
) : null}
|
||||
{playerData.topBrellaScore ? (
|
||||
<>
|
||||
<i>Brella Power: {playerData.topBrellaScore}</i>
|
||||
<br />
|
||||
</>
|
||||
) : null}
|
||||
<Segment compact>
|
||||
<div style={{"padding": "5px"}}>
|
||||
<TopPlacementTable top={top}/>
|
||||
</div>
|
||||
</Segment>
|
||||
<Segment compact>
|
||||
<div style={{"padding": "5px"}}>
|
||||
<Header dividing>All Top 500 placements</Header>
|
||||
<MonthsTable placements={data.playerInfo.placements} />
|
||||
</div>
|
||||
</Segment>
|
||||
<Segment compact>
|
||||
<div style={{"padding": "5px"}}>
|
||||
<Header dividing>Weapons reached Top 500 with</Header>
|
||||
<WpnPlayedTable weapons={playerData.weapons} />
|
||||
</div>
|
||||
</Segment>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default InfoPlayer
|
||||
export default InfoPlayer
|
||||
|
|
|
|||
36
react-ui/src/components/XSearch/InfoWeapon.js
vendored
|
|
@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react'
|
|||
import { useQuery } from 'react-apollo-hooks'
|
||||
import { topPlayersOfWeapon } from '../../graphql/queries/topPlayersOfWeapon'
|
||||
import weaponDictReversed from '../../utils/internal_english.json'
|
||||
import { Loader, Header, Table, Checkbox } from 'semantic-ui-react'
|
||||
import { Loader, Header, Table, Checkbox, Segment } from 'semantic-ui-react'
|
||||
import { withRouter, Link } from 'react-router-dom'
|
||||
|
||||
import szIcon from '../img/modeIcons/sz.png'
|
||||
|
|
@ -58,22 +58,24 @@ const InfoWeapon = withRouter(({ history, wpn }) => {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<div style={{"paddingTop": "20px", "paddingBottom": "20px"}}>
|
||||
<Header size='large'>
|
||||
<img
|
||||
src={`https://raw.githubusercontent.com/Leanny/leanny.github.io/master/splat2/weapons/Wst_${wpn}.png`}
|
||||
alt={weaponDictReversed[wpn]}
|
||||
/> {weaponDictReversed[wpn]} Leaderboard
|
||||
</Header>
|
||||
<Header size='tiny'>
|
||||
<b>Times in Top 500:</b>
|
||||
<img src={modeIcons[1]} style={{"paddingLeft": "10px"}} alt="Splat Zones logo" /> {modeCount[1]}
|
||||
<img src={modeIcons[2]} style={{"paddingLeft": "10px"}} alt="Tower Control logo" /> {modeCount[2]}
|
||||
<img src={modeIcons[3]} style={{"paddingLeft": "10px"}} alt="Rainmaker logo" /> {modeCount[3]}
|
||||
<img src={modeIcons[4]} style={{"paddingLeft": "10px"}} alt="Clam Blitz logo" /> {modeCount[4]}<br/>
|
||||
Total {modeCount[0]}
|
||||
</Header>
|
||||
</div>
|
||||
<Segment compact>
|
||||
<div style={{"padding": "5px"}}>
|
||||
<Header size='large'>
|
||||
<img
|
||||
src={`https://raw.githubusercontent.com/Leanny/leanny.github.io/master/splat2/weapons/Wst_${wpn}.png`}
|
||||
alt={weaponDictReversed[wpn]}
|
||||
/> {weaponDictReversed[wpn]} Leaderboard
|
||||
</Header>
|
||||
<Header size='tiny'>
|
||||
<b>Times in Top 500:</b>
|
||||
<img src={modeIcons[1]} style={{"paddingLeft": "10px"}} alt="Splat Zones logo" /> {modeCount[1]}
|
||||
<img src={modeIcons[2]} style={{"paddingLeft": "10px"}} alt="Tower Control logo" /> {modeCount[2]}
|
||||
<img src={modeIcons[3]} style={{"paddingLeft": "10px"}} alt="Rainmaker logo" /> {modeCount[3]}
|
||||
<img src={modeIcons[4]} style={{"paddingLeft": "10px"}} alt="Clam Blitz logo" /> {modeCount[4]}<br/>
|
||||
Total {modeCount[0]}
|
||||
</Header>
|
||||
</div>
|
||||
</Segment>
|
||||
<div>
|
||||
<Checkbox
|
||||
radio
|
||||
|
|
|
|||
393
react-ui/src/components/XSearch/WeaponForm.js
vendored
|
|
@ -1,48 +1,369 @@
|
|||
import React, { useState } from 'react'
|
||||
import { Dropdown, Button } from 'semantic-ui-react'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import { weapons } from '../../utils/lists'
|
||||
import weaponDict from '../../utils/english_internal.json'
|
||||
import React, { useState } from "react"
|
||||
import { Dropdown, Button } from "semantic-ui-react"
|
||||
import { withRouter } from "react-router-dom"
|
||||
import { weapons } from "../../utils/lists"
|
||||
import weaponDict from "../../utils/english_internal.json"
|
||||
|
||||
const WeaponForm = withRouter(({ history, weaponForm, setWeaponForm, showImages=true, push=false, setPage }) => {
|
||||
return (
|
||||
<div>
|
||||
<Dropdown
|
||||
placeholder='Choose a weapon'
|
||||
fluid
|
||||
search
|
||||
selection
|
||||
options={weapons.map(w =>
|
||||
(
|
||||
{key: w,
|
||||
text: w,
|
||||
value: w,
|
||||
image: showImages ? {src: process.env.PUBLIC_URL + `/wpnSmall/Wst_${weaponDict[w]}.png`} : null
|
||||
const WeaponForm = withRouter(
|
||||
({
|
||||
history,
|
||||
weaponForm,
|
||||
setWeaponForm,
|
||||
showImages = true,
|
||||
push = false,
|
||||
setPage,
|
||||
showSubSpecials = false
|
||||
}) => {
|
||||
const subSpecialOptions = [
|
||||
{
|
||||
key: "Splat Bomb",
|
||||
text: "Splat Bomb",
|
||||
value: "Splat Bomb",
|
||||
image: showImages
|
||||
? {
|
||||
src:
|
||||
process.env.PUBLIC_URL + `/wpnSmall/Wst_Bomb_Splash.png`
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
onChange={(event, { value }) => {
|
||||
setWeaponForm(value)
|
||||
if (push) history.push(`/builds/${value.replace(/ /g, '_')}`)
|
||||
if (setPage) setPage(1)
|
||||
}}
|
||||
value={weaponForm}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Suction Bomb",
|
||||
text: "Suction Bomb",
|
||||
value: "Suction Bomb",
|
||||
image: showImages
|
||||
? {
|
||||
src:
|
||||
process.env.PUBLIC_URL + `/wpnSmall/Wst_Bomb_Suction.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Burst Bomb",
|
||||
text: "Burst Bomb",
|
||||
value: "Burst Bomb",
|
||||
image: showImages
|
||||
? {
|
||||
src:
|
||||
process.env.PUBLIC_URL + `/wpnSmall/Wst_Bomb_Quick.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Curling Bomb",
|
||||
text: "Curling Bomb",
|
||||
value: "Curling Bomb",
|
||||
image: showImages
|
||||
? {
|
||||
src:
|
||||
process.env.PUBLIC_URL + `/wpnSmall/Wst_Bomb_Curling.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Autobomb",
|
||||
text: "Autobomb",
|
||||
value: "Autobomb",
|
||||
image: showImages
|
||||
? {
|
||||
src: process.env.PUBLIC_URL + `/wpnSmall/Wst_Bomb_Robo.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Ink Mine",
|
||||
text: "Ink Mine",
|
||||
value: "Ink Mine",
|
||||
image: showImages
|
||||
? {
|
||||
src: process.env.PUBLIC_URL + `/wpnSmall/Wst_TimerTrap.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Toxic Mist",
|
||||
text: "Toxic Mist",
|
||||
value: "Toxic Mist",
|
||||
image: showImages
|
||||
? {
|
||||
src: process.env.PUBLIC_URL + `/wpnSmall/Wst_PoisonFog.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Point Sensor",
|
||||
text: "Point Sensor",
|
||||
value: "Point Sensor",
|
||||
image: showImages
|
||||
? {
|
||||
src:
|
||||
process.env.PUBLIC_URL + `/wpnSmall/Wst_PointSensor.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Splash Wall",
|
||||
text: "Splash Wall",
|
||||
value: "Splash Wall",
|
||||
image: showImages
|
||||
? {
|
||||
src: process.env.PUBLIC_URL + `/wpnSmall/Wst_Shield.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Sprinkler",
|
||||
text: "Sprinkler",
|
||||
value: "Sprinkler",
|
||||
image: showImages
|
||||
? {
|
||||
src: process.env.PUBLIC_URL + `/wpnSmall/Wst_Sprinkler.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Squid Beakon",
|
||||
text: "Squid Beakon",
|
||||
value: "Squid Beakon",
|
||||
image: showImages
|
||||
? {
|
||||
src: process.env.PUBLIC_URL + `/wpnSmall/Wst_Flag.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Fizzy Bomb",
|
||||
text: "Fizzy Bomb",
|
||||
value: "Fizzy Bomb",
|
||||
image: showImages
|
||||
? {
|
||||
src: process.env.PUBLIC_URL + `/wpnSmall/Wst_Bomb_Piyo.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Torpedo",
|
||||
text: "Torpedo",
|
||||
value: "Torpedo",
|
||||
image: showImages
|
||||
? {
|
||||
src: process.env.PUBLIC_URL + `/wpnSmall/Wst_Bomb_Tako.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Tenta Missiles",
|
||||
text: "Tenta Missiles",
|
||||
value: "Tenta Missiles",
|
||||
image: showImages
|
||||
? {
|
||||
src:
|
||||
process.env.PUBLIC_URL + `/wpnSmall/Wst_SuperMissile.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Sting Ray",
|
||||
text: "Sting Ray",
|
||||
value: "Sting Ray",
|
||||
image: showImages
|
||||
? {
|
||||
src:
|
||||
process.env.PUBLIC_URL + `/wpnSmall/Wst_WaterCutter.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Inkjet",
|
||||
text: "Inkjet",
|
||||
value: "Inkjet",
|
||||
image: showImages
|
||||
? {
|
||||
src: process.env.PUBLIC_URL + `/wpnSmall/Wst_Jetpack.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Splashdown",
|
||||
text: "Splashdown",
|
||||
value: "Splashdown",
|
||||
image: showImages
|
||||
? {
|
||||
src:
|
||||
process.env.PUBLIC_URL + `/wpnSmall/Wst_SuperLanding.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Ink Armor",
|
||||
text: "Ink Armor",
|
||||
value: "Ink Armor",
|
||||
image: showImages
|
||||
? {
|
||||
src:
|
||||
process.env.PUBLIC_URL + `/wpnSmall/Wst_SuperArmor.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Autobomb Launcher",
|
||||
text: "Autobomb Launcher",
|
||||
value: "Autobomb Launcher",
|
||||
image: showImages
|
||||
? {
|
||||
src:
|
||||
process.env.PUBLIC_URL + `/wpnSmall/Wst_LauncherRobo.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Burst-Bomb Launcher",
|
||||
text: "Burst-Bomb Launcher",
|
||||
value: "Burst-Bomb Launcher",
|
||||
image: showImages
|
||||
? {
|
||||
src:
|
||||
process.env.PUBLIC_URL +
|
||||
`/wpnSmall/Wst_LauncherQuick.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Curling-Bomb Launcher",
|
||||
text: "Curling-Bomb Launcher",
|
||||
value: "Curling-Bomb Launcher",
|
||||
image: showImages
|
||||
? {
|
||||
src:
|
||||
process.env.PUBLIC_URL +
|
||||
`/wpnSmall/Wst_LauncherCurling.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Splat-Bomb Launcher",
|
||||
text: "Splat-Bomb Launcher",
|
||||
value: "Splat-Bomb Launcher",
|
||||
image: showImages
|
||||
? {
|
||||
src:
|
||||
process.env.PUBLIC_URL +
|
||||
`/wpnSmall/Wst_LauncherSplash.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Suction-Bomb Launcher",
|
||||
text: "Suction-Bomb Launcher",
|
||||
value: "Suction-Bomb Launcher",
|
||||
image: showImages
|
||||
? {
|
||||
src:
|
||||
process.env.PUBLIC_URL +
|
||||
`/wpnSmall/Wst_LauncherSuction.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Ink Storm",
|
||||
text: "Ink Storm",
|
||||
value: "Ink Storm",
|
||||
image: showImages
|
||||
? {
|
||||
src: process.env.PUBLIC_URL + `/wpnSmall/Wst_RainCloud.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Baller",
|
||||
text: "Baller",
|
||||
value: "Baller",
|
||||
image: showImages
|
||||
? {
|
||||
src: process.env.PUBLIC_URL + `/wpnSmall/Wst_AquaBall.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Bubble Blower",
|
||||
text: "Bubble Blower",
|
||||
value: "Bubble Blower",
|
||||
image: showImages
|
||||
? {
|
||||
src:
|
||||
process.env.PUBLIC_URL + `/wpnSmall/Wst_SuperBubble.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Booyah Bomb",
|
||||
text: "Booyah Bomb",
|
||||
value: "Booyah Bomb",
|
||||
image: showImages
|
||||
? {
|
||||
src: process.env.PUBLIC_URL + `/wpnSmall/Wst_SuperBall.png`
|
||||
}
|
||||
: null
|
||||
},
|
||||
{
|
||||
key: "Ultra Stamp",
|
||||
text: "Ultra Stamp",
|
||||
value: "Ultra Stamp",
|
||||
image: showImages
|
||||
? {
|
||||
src:
|
||||
process.env.PUBLIC_URL + `/wpnSmall/Wst_SuperStamp.png`
|
||||
}
|
||||
: null
|
||||
}
|
||||
]
|
||||
let options = weapons.map(w => ({
|
||||
key: w,
|
||||
text: w,
|
||||
value: w,
|
||||
image: showImages
|
||||
? { src: process.env.PUBLIC_URL + `/wpnSmall/Wst_${weaponDict[w]}.png` }
|
||||
: null
|
||||
}))
|
||||
if (showSubSpecials) options = options.concat(subSpecialOptions)
|
||||
return (
|
||||
<div>
|
||||
<Dropdown
|
||||
placeholder="Choose a weapon"
|
||||
fluid
|
||||
search
|
||||
selection
|
||||
options={options}
|
||||
onChange={(event, { value }) => {
|
||||
setWeaponForm(value)
|
||||
if (push) history.push(`/builds/${value.replace(/ /g, "_")}`)
|
||||
if (setPage) setPage(1)
|
||||
}}
|
||||
value={weaponForm}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
export const WeaponFormWithButton = withRouter(({ history }) => {
|
||||
const [weaponForm, setWeaponForm] = useState('')
|
||||
const [weaponForm, setWeaponForm] = useState("")
|
||||
return (
|
||||
<div>
|
||||
<WeaponForm weaponForm={weaponForm} setWeaponForm={setWeaponForm} />
|
||||
<div style={{"paddingTop": "13px"}}>
|
||||
<Button disabled={weaponForm === ''} onClick={() => history.push(`/xsearch/w/${weaponDict[weaponForm].replace(/_/g, '-')}`)}>Search for a weapon</Button>
|
||||
<div style={{ paddingTop: "13px" }}>
|
||||
<Button
|
||||
disabled={weaponForm === ""}
|
||||
onClick={() =>
|
||||
history.push(
|
||||
`/xsearch/w/${weaponDict[weaponForm].replace(/_/g, "-")}`
|
||||
)
|
||||
}
|
||||
>
|
||||
Search for a weapon
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
export default WeaponForm
|
||||
export default WeaponForm
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ const XSearchResults = withRouter(({ history, name, exact }) => {
|
|||
error
|
||||
header='Found 0 players who reached Top 500 with your search'
|
||||
list={[
|
||||
'You can\'t search for a player that has never finished in the Top 500',
|
||||
'You can\'t search for a player who has never finished in the Top 500',
|
||||
'Be careful about special characters: ρ is not the same as p for example',
|
||||
'Some characters can\'t be used in the search such as )'
|
||||
]}
|
||||
|
|
|
|||
359
react-ui/src/components/XSearch/XTrends.js
vendored
Normal file
|
|
@ -0,0 +1,359 @@
|
|||
import React, { useState, useEffect } from "react"
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
Radio,
|
||||
Segment,
|
||||
List,
|
||||
Image,
|
||||
Grid,
|
||||
Dropdown
|
||||
} from "semantic-ui-react"
|
||||
import WeaponForm from "./WeaponForm"
|
||||
import useTrends from "../hooks/useTrends"
|
||||
import useWindowDimensions from "../hooks/useWindowDimensions"
|
||||
import english_internal from "../../utils/english_internal.json"
|
||||
import {
|
||||
LineChart,
|
||||
Line,
|
||||
XAxis,
|
||||
YAxis,
|
||||
CartesianGrid,
|
||||
Tooltip,
|
||||
Legend,
|
||||
Brush
|
||||
} from "recharts"
|
||||
|
||||
const circleStyle = {
|
||||
width: "25px",
|
||||
height: "25px",
|
||||
WebkitBorderRadius: "12.5px",
|
||||
MozBorderRadius: "12.5px",
|
||||
borderRadius: "12.5px"
|
||||
}
|
||||
|
||||
const customToolTipStyle = {
|
||||
width: "200px",
|
||||
margin: "0",
|
||||
lineHeight: "24px",
|
||||
border: "1px solid #f5f5f5",
|
||||
backgroundColor: "hsla(0,0%,100%,.8)",
|
||||
padding: "10px"
|
||||
}
|
||||
|
||||
const labelStyle = {
|
||||
margin: "0",
|
||||
color: "#666",
|
||||
fontWeight: "700"
|
||||
}
|
||||
|
||||
const introStyle = {
|
||||
borderTop: "1px solid #f5f5f5",
|
||||
margin: "0"
|
||||
}
|
||||
|
||||
const descStyle = {
|
||||
margin: 0,
|
||||
color: "#999"
|
||||
}
|
||||
|
||||
const months = [
|
||||
null,
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December"
|
||||
]
|
||||
|
||||
const XTrends = ({ setMenuSelection }) => {
|
||||
const [weaponForm, setWeaponForm] = useState(null)
|
||||
const [combineFormLeft, setCombineFormLeft] = useState(null)
|
||||
const [combineFormRight, setCombineFormRight] = useState(null)
|
||||
const [weaponForDispatch, setWeaponForDispatch] = useState(null)
|
||||
const [mode, setMode] = useState("ALL")
|
||||
const [modeForDispatch, setModeForDispatch] = useState(null)
|
||||
const { loading, error, plotData, dispatch } = useTrends(
|
||||
weaponForDispatch,
|
||||
modeForDispatch
|
||||
)
|
||||
const { containerWidth } = useWindowDimensions()
|
||||
|
||||
useEffect(() => {
|
||||
setMenuSelection("trends")
|
||||
document.title = "X Rank Trends - sendou.ink"
|
||||
}, [setMenuSelection])
|
||||
|
||||
const CustomTooltip = ({ active, payload, label }) => {
|
||||
if (active) {
|
||||
const monthNumber = payload[0].payload.name
|
||||
const yearNumber = payload[0].payload.year
|
||||
let patchDescription = null
|
||||
if (payload[0].payload.hasOwnProperty("patch")) {
|
||||
if (monthNumber === 4 && yearNumber === 2019) {
|
||||
patchDescription = "Patches 4.6 and 4.7 were released."
|
||||
} else {
|
||||
patchDescription = `Patch ${payload[0].payload.patch} was released.`
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div style={customToolTipStyle}>
|
||||
<p style={labelStyle}>{`${months[monthNumber]} (${yearNumber})`}</p>
|
||||
{payload.map(p => {
|
||||
return (
|
||||
<p style={{ ...introStyle, color: p.stroke }} key={p.dataKey}>
|
||||
{p.payload[p.dataKey]} - {p.dataKey}
|
||||
</p>
|
||||
)
|
||||
})}
|
||||
{patchDescription && <p style={descStyle}>{patchDescription}</p>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Segment>
|
||||
<div style={{ padding: "5px" }}>
|
||||
<WeaponForm
|
||||
showSubSpecials
|
||||
weaponForm={weaponForm}
|
||||
setWeaponForm={setWeaponForm}
|
||||
/>
|
||||
<div style={{ paddingTop: "10px" }}>
|
||||
<Form>
|
||||
<Form.Field>
|
||||
<Radio
|
||||
label="All Modes"
|
||||
name="radioGroup"
|
||||
value="ALL"
|
||||
checked={mode === "ALL"}
|
||||
onChange={() => setMode("ALL")}
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Radio
|
||||
label="Splat Zones"
|
||||
name="radioGroup"
|
||||
value="SZ"
|
||||
checked={mode === "SZ"}
|
||||
onChange={() => setMode("SZ")}
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Radio
|
||||
label="Tower Control"
|
||||
name="radioGroup"
|
||||
value="TC"
|
||||
checked={mode === "TC"}
|
||||
onChange={() => setMode("TC")}
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Radio
|
||||
label="Rainmaker"
|
||||
name="radioGroup"
|
||||
value="RM"
|
||||
checked={mode === "RM"}
|
||||
onChange={() => setMode("RM")}
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Radio
|
||||
label="Clam Blitz"
|
||||
name="radioGroup"
|
||||
value="CB"
|
||||
checked={mode === "CB"}
|
||||
onChange={() => setMode("CB")}
|
||||
/>
|
||||
</Form.Field>
|
||||
</Form>
|
||||
</div>
|
||||
<div style={{ paddingTop: "10px" }}>
|
||||
<Button
|
||||
loading={loading}
|
||||
onClick={() => {
|
||||
setWeaponForDispatch(weaponForm)
|
||||
setModeForDispatch(mode)
|
||||
const wpnForCombine =
|
||||
mode === "ALL" ? weaponForm : `${weaponForm} (${mode})`
|
||||
setCombineFormLeft(wpnForCombine)
|
||||
if (plotData.keys.length >= 1)
|
||||
setCombineFormRight(
|
||||
plotData.keys[plotData.keys.length - 1].weapon
|
||||
)
|
||||
}}
|
||||
disabled={!weaponForm}
|
||||
>
|
||||
Add to plot as new
|
||||
</Button>
|
||||
{plotData.keys.length >= 2 && (
|
||||
<div style={{ paddingTop: "10px" }}>
|
||||
<Button
|
||||
disabled={
|
||||
!combineFormLeft ||
|
||||
!combineFormRight ||
|
||||
combineFormLeft === combineFormRight
|
||||
}
|
||||
onClick={() => {
|
||||
dispatch({
|
||||
type: "combine",
|
||||
left: combineFormLeft,
|
||||
right: combineFormRight
|
||||
})
|
||||
}}
|
||||
>
|
||||
Combine...
|
||||
</Button>
|
||||
<span>
|
||||
{" "}
|
||||
<Dropdown
|
||||
inline
|
||||
options={plotData.keys
|
||||
.map(k => {
|
||||
return { text: k.weapon, value: k.weapon }
|
||||
})
|
||||
.filter(k => k.text !== combineFormRight)}
|
||||
onChange={(event, { value }) => {
|
||||
setCombineFormLeft(value)
|
||||
}}
|
||||
value={combineFormLeft}
|
||||
/>{" "}
|
||||
with{" "}
|
||||
<Dropdown
|
||||
inline
|
||||
options={plotData.keys
|
||||
.map(k => {
|
||||
return { text: k.weapon, value: k.weapon }
|
||||
})
|
||||
.filter(k => k.text !== combineFormLeft)}
|
||||
onChange={(event, { value }) => {
|
||||
setCombineFormRight(value)
|
||||
}}
|
||||
value={combineFormRight}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{plotData.keys.length > 0 && (
|
||||
<div style={{ paddingTop: "10px" }}>
|
||||
<LineChart
|
||||
width={containerWidth}
|
||||
height={500}
|
||||
data={plotData.data}
|
||||
margin={{
|
||||
top: 5,
|
||||
right: 50,
|
||||
left: 0,
|
||||
bottom: 5
|
||||
}}
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey="xLabel" tickLine={false} />
|
||||
<XAxis
|
||||
dataKey="patch"
|
||||
tickLine={true}
|
||||
scale="band"
|
||||
axisLine={false}
|
||||
height={1}
|
||||
xAxisId="patch"
|
||||
/>
|
||||
<YAxis
|
||||
allowDecimals={false}
|
||||
label={{
|
||||
value: "X rank top 500 placements",
|
||||
angle: -90,
|
||||
position: "insideLeft",
|
||||
textAnchor: "middle"
|
||||
}}
|
||||
/>
|
||||
<Tooltip content={<CustomTooltip />} />
|
||||
<Legend verticalAlign="top" />
|
||||
<Brush dataKey="xLabel" height={75} stroke="#000000" />
|
||||
{plotData.keys.map(keyObj => {
|
||||
const w = keyObj.weapon
|
||||
const color = keyObj.color
|
||||
return (
|
||||
<Line key={w} type="monotone" dataKey={w} stroke={color} />
|
||||
)
|
||||
})}
|
||||
</LineChart>
|
||||
<Grid columns={2} style={{ paddingTop: "10px" }}>
|
||||
<Grid.Column>
|
||||
<List divided verticalAlign="middle">
|
||||
{plotData.keys.map(keyObj => {
|
||||
const w = keyObj.weapon
|
||||
const color = keyObj.color
|
||||
return (
|
||||
<List.Item key={w}>
|
||||
<List.Content floated="right">
|
||||
<Button
|
||||
circular
|
||||
size="mini"
|
||||
negative
|
||||
icon="trash"
|
||||
onClick={() =>
|
||||
dispatch({ type: "delete", weapon: w })
|
||||
}
|
||||
/>
|
||||
</List.Content>
|
||||
{w.indexOf("+") === -1 && (
|
||||
<Image
|
||||
avatar
|
||||
src={`/wpnSmall/Wst_${
|
||||
english_internal[
|
||||
w
|
||||
.replace(" (SZ)", "")
|
||||
.replace(" (TC)", "")
|
||||
.replace(" (RM)", "")
|
||||
.replace(" (CB)", "")
|
||||
]
|
||||
}.png`}
|
||||
/>
|
||||
)}
|
||||
<List.Content>
|
||||
<span
|
||||
style={{
|
||||
color: color,
|
||||
background: "none",
|
||||
border: "none",
|
||||
cursor: "pointer",
|
||||
WebkitUserSelect: "none",
|
||||
MozUserSelect: "none",
|
||||
MsUserSelect: "none",
|
||||
userSelect: "none"
|
||||
}}
|
||||
onClick={() =>
|
||||
dispatch({ type: "randomizeColor", weapon: w })
|
||||
}
|
||||
>
|
||||
{w}
|
||||
</span>
|
||||
</List.Content>
|
||||
</List.Item>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
</Grid.Column>
|
||||
<Grid.Column />
|
||||
</Grid>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Segment>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default XTrends
|
||||
278
react-ui/src/components/hooks/useTrends.js
vendored
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
import { useReducer, useEffect } from "react"
|
||||
import { useQuery } from "react-apollo-hooks"
|
||||
import { searchForTrend } from "../../graphql/queries/seachForTrend"
|
||||
|
||||
const month = []
|
||||
month[0] = null
|
||||
month[1] = "Jan"
|
||||
month[2] = "Feb"
|
||||
month[3] = "Mar"
|
||||
month[4] = "Apr"
|
||||
month[5] = "May"
|
||||
month[6] = "Jun"
|
||||
month[7] = "Jul"
|
||||
month[8] = "Aug"
|
||||
month[9] = "Sep"
|
||||
month[10] = "Oct"
|
||||
month[11] = "Nov"
|
||||
month[12] = "Dec"
|
||||
|
||||
const patches = {
|
||||
5: {
|
||||
2018: {
|
||||
name: "3.0",
|
||||
link: "https://splatoonwiki.org/wiki/Version_3.0.0_(Splatoon_2)"
|
||||
},
|
||||
2019: {
|
||||
name: "4.8",
|
||||
link: "https://splatoonwiki.org/wiki/Version_4.8.0_(Splatoon_2)"
|
||||
}
|
||||
},
|
||||
6: {
|
||||
2018: {
|
||||
name: "3.1",
|
||||
link: "https://splatoonwiki.org/wiki/Version_3.1.0_(Splatoon_2)"
|
||||
},
|
||||
2019: {
|
||||
name: "4.9",
|
||||
link: "https://splatoonwiki.org/wiki/Version_4.9.0_(Splatoon_2)"
|
||||
}
|
||||
},
|
||||
7: {
|
||||
2018: {
|
||||
name: "3.2",
|
||||
link: "https://splatoonwiki.org/wiki/Version_3.2.0_(Splatoon_2)"
|
||||
},
|
||||
2019: {
|
||||
name: "5.0",
|
||||
link: "https://splatoonwiki.org/wiki/Version_5.0.0_(Splatoon_2)"
|
||||
}
|
||||
},
|
||||
9: {
|
||||
2018: {
|
||||
name: "4.0",
|
||||
link: "https://splatoonwiki.org/wiki/Version_4.0.0_(Splatoon_2)"
|
||||
}
|
||||
},
|
||||
10: {
|
||||
2018: {
|
||||
name: "4.1",
|
||||
link: "https://splatoonwiki.org/wiki/Version_4.1.0_(Splatoon_2)"
|
||||
}
|
||||
},
|
||||
11: {
|
||||
2018: {
|
||||
name: "4.2",
|
||||
link: "https://splatoonwiki.org/wiki/Version_4.2.0_(Splatoon_2)"
|
||||
}
|
||||
},
|
||||
12: {
|
||||
2018: {
|
||||
name: "4.3",
|
||||
link: "https://splatoonwiki.org/wiki/Version_4.3.0_(Splatoon_2)"
|
||||
}
|
||||
},
|
||||
1: {
|
||||
2019: {
|
||||
name: "4.4",
|
||||
link: "https://splatoonwiki.org/wiki/Version_4.4.0_(Splatoon_2)"
|
||||
}
|
||||
},
|
||||
3: {
|
||||
2019: {
|
||||
name: "4.5",
|
||||
link: "https://splatoonwiki.org/wiki/Version_4.5.0_(Splatoon_2)"
|
||||
}
|
||||
},
|
||||
4: {
|
||||
2019: {
|
||||
name: "4.6+4.7",
|
||||
link: "https://splatoonwiki.org/wiki/List_of_updates_in_Splatoon_2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const presetColors = [
|
||||
"#FF00FF",
|
||||
"#008000",
|
||||
"#FF0000",
|
||||
"#0000FF",
|
||||
"#FFA500",
|
||||
"#800080",
|
||||
"#A52A2A",
|
||||
"#1BC5CD",
|
||||
"#000080",
|
||||
"#5BCCA0"
|
||||
]
|
||||
|
||||
const setPlotDataInitial = () => {
|
||||
const arr_to_return = []
|
||||
for (let i = 5; i < 13; i++) {
|
||||
if (patches.hasOwnProperty(i) && patches[i].hasOwnProperty(2018)) {
|
||||
arr_to_return.push({
|
||||
name: i,
|
||||
year: 2018,
|
||||
xLabel: month[i],
|
||||
patch: patches[i][2018].name
|
||||
})
|
||||
} else {
|
||||
arr_to_return.push({ name: i, year: 2018, xLabel: month[i] })
|
||||
}
|
||||
}
|
||||
const d = new Date()
|
||||
const year = d.getFullYear()
|
||||
const currentMonth = d.getMonth() + 1
|
||||
for (let i = 2019; i < year + 1; i++) {
|
||||
for (let j = 1; j < 13; j++) {
|
||||
// break the loop when we reach the future
|
||||
if (i === year && j === currentMonth) break
|
||||
const xLabel = j === 1 ? `Jan (${year})` : month[j]
|
||||
if (patches.hasOwnProperty(j) && patches[j].hasOwnProperty(i)) {
|
||||
arr_to_return.push({
|
||||
name: j,
|
||||
year: i,
|
||||
xLabel,
|
||||
patch: patches[j][i].name
|
||||
})
|
||||
} else {
|
||||
arr_to_return.push({ name: j, year: i, xLabel })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return arr_to_return
|
||||
}
|
||||
|
||||
const mergeModeArrays = countObj => {
|
||||
const sz_arr = countObj["SZ"]
|
||||
const tc_arr = countObj["TC"]
|
||||
const rm_arr = countObj["RM"]
|
||||
const cb_arr = countObj["CB"]
|
||||
const arr_to_return = new Array(12).fill(0)
|
||||
for (let i = 1; i < 13; i++) {
|
||||
arr_to_return[i] = sz_arr[i] + tc_arr[i] + rm_arr[i] + cb_arr[i]
|
||||
}
|
||||
return arr_to_return
|
||||
}
|
||||
|
||||
// monthIndex is between 1 and 12 (inclusive)
|
||||
const resolveStartIndex = (monthIndex, year) => {
|
||||
// resolves start index for an array where index 0 is always May 2018
|
||||
if (year === 2018) {
|
||||
return monthIndex - 5
|
||||
} else if (year === 2019) {
|
||||
return 7 + monthIndex
|
||||
} else {
|
||||
return 7 + monthIndex + (year - 2019) * 12
|
||||
}
|
||||
}
|
||||
|
||||
const getColor = state => {
|
||||
if (state.keys.length < 9) {
|
||||
return presetColors[state.keys.length]
|
||||
}
|
||||
|
||||
return "#000000".replace(/0/g, function() {
|
||||
return (~~(Math.random() * 16)).toString(16)
|
||||
})
|
||||
}
|
||||
|
||||
const reducer = (state, action) => {
|
||||
switch (action.type) {
|
||||
case "add":
|
||||
const trend = action.trendDocument
|
||||
const mode = action.mode
|
||||
const modeLabel = mode === "ALL" ? "" : ` (${mode})`
|
||||
const weapon = `${action.trendDocument.weapon}${modeLabel}`
|
||||
// don't add duplicate plots
|
||||
if (state.keys.indexOf(weapon) !== -1) return state
|
||||
const toPlotData = [...state.data]
|
||||
for (let index = 0; index < trend.counts.length; index++) {
|
||||
let year = trend.counts[index].year
|
||||
let year_arr = null
|
||||
if (mode === "ALL") {
|
||||
year_arr = mergeModeArrays(trend.counts[index])
|
||||
} else {
|
||||
year_arr = trend.counts[index][mode]
|
||||
}
|
||||
|
||||
for (let i = 1; i < 13; i++) {
|
||||
// if year is 2018 skipping to the index where values are found
|
||||
if (year === 2018 && i < 5) {
|
||||
i = 4
|
||||
continue
|
||||
}
|
||||
const plotIndex = resolveStartIndex(i, year)
|
||||
if (plotIndex === toPlotData.length) break
|
||||
toPlotData[plotIndex][weapon] = year_arr[i]
|
||||
}
|
||||
}
|
||||
|
||||
const keyObj = {
|
||||
weapon,
|
||||
color: getColor(state)
|
||||
}
|
||||
return { data: toPlotData, keys: [...state.keys, keyObj] }
|
||||
case "delete":
|
||||
const weaponToDelete = action.weapon
|
||||
const newKeys = [...state.keys].filter(k => k.weapon !== weaponToDelete)
|
||||
return { data: state.data, keys: newKeys }
|
||||
case "combine":
|
||||
const weaponLeft = action.left
|
||||
const weaponRight = action.right
|
||||
const newKey = `${weaponLeft} + ${weaponRight}`
|
||||
const newKeysWithCombined = [
|
||||
...state.keys,
|
||||
{ weapon: newKey, color: getColor(state) }
|
||||
].filter(k => k.weapon !== weaponLeft && k.weapon !== weaponRight)
|
||||
const newDataWithCombined = [...state.data].map(d => {
|
||||
const dataObj = { ...d }
|
||||
let weaponLeftCount = 0
|
||||
let weaponRightCount = 0
|
||||
if (dataObj.hasOwnProperty(weaponLeft))
|
||||
weaponLeftCount = dataObj[weaponLeft]
|
||||
if (dataObj.hasOwnProperty(weaponRight))
|
||||
weaponRightCount = dataObj[weaponRight]
|
||||
dataObj[newKey] = weaponLeftCount + weaponRightCount
|
||||
delete dataObj[weaponLeft]
|
||||
delete dataObj[weaponRight]
|
||||
return dataObj
|
||||
})
|
||||
|
||||
return { data: newDataWithCombined, keys: newKeysWithCombined }
|
||||
case "randomizeColor":
|
||||
const keysWithNewColor = [...state.keys].map(k => {
|
||||
if (k.weapon !== action.weapon) {
|
||||
return k
|
||||
}
|
||||
return {
|
||||
...k,
|
||||
color: "#000000".replace(/0/g, function() {
|
||||
return (~~(Math.random() * 16)).toString(16)
|
||||
})
|
||||
}
|
||||
})
|
||||
return { data: state.data, keys: keysWithNewColor }
|
||||
default:
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
|
||||
export default function useTrends(weapon, mode) {
|
||||
const [plotData, dispatch] = useReducer(reducer, {
|
||||
data: setPlotDataInitial(),
|
||||
keys: []
|
||||
})
|
||||
// Skip query if there is no weapon provided
|
||||
const { data, loading, error } = useQuery(searchForTrend, {
|
||||
skip: !weapon,
|
||||
variables: { weapon }
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (loading || !data) return
|
||||
dispatch({ type: "add", trendDocument: data.searchForTrend, mode })
|
||||
}, [loading, data, mode])
|
||||
|
||||
return { loading, error, plotData, dispatch }
|
||||
}
|
||||
|
Before Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 820 KiB After Width: | Height: | Size: 828 KiB |
|
Before Width: | Height: | Size: 721 KiB After Width: | Height: | Size: 825 KiB |
16
react-ui/src/graphql/queries/seachForTrend.js
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { gql } from 'apollo-boost'
|
||||
|
||||
export const searchForTrend = gql`
|
||||
query searchForTrend($weapon: String!) {
|
||||
searchForTrend(weapon: $weapon) {
|
||||
weapon
|
||||
counts {
|
||||
year
|
||||
SZ
|
||||
TC
|
||||
RM
|
||||
CB
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
@ -9,6 +9,7 @@ const { Player, playerResolvers } = require('./schemas/player')
|
|||
const { Rotation, rotationResolvers } = require('./schemas/rotation')
|
||||
const { User, userResolvers } = require('./schemas/user')
|
||||
const { Link, linkResolvers } = require('./schemas/link')
|
||||
const { Trend, trendResolvers } = require('./schemas/trend')
|
||||
|
||||
const Query = gql`
|
||||
type Query {
|
||||
|
|
@ -34,7 +35,8 @@ const schema = makeExecutableSchema({
|
|||
Player,
|
||||
Rotation,
|
||||
User,
|
||||
Link ],
|
||||
Link,
|
||||
Trend ],
|
||||
resolvers: merge(
|
||||
resolvers,
|
||||
buildResolvers,
|
||||
|
|
@ -43,7 +45,8 @@ const schema = makeExecutableSchema({
|
|||
playerResolvers,
|
||||
rotationResolvers,
|
||||
userResolvers,
|
||||
linkResolvers
|
||||
linkResolvers,
|
||||
trendResolvers
|
||||
)
|
||||
})
|
||||
|
||||
|
|
|
|||
42
schemas/trend.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
const { UserInputError, gql } = require('apollo-server-express')
|
||||
const Trend = require('../models/trend')
|
||||
|
||||
const typeDef = gql`
|
||||
extend type Query {
|
||||
searchForTrend(weapon: String!): Trend
|
||||
}
|
||||
type Year {
|
||||
year: Int!
|
||||
"Array that has length of 13. 0 index = null. Other indexes correspond months e.g. index 1 = January."
|
||||
SZ: [Int]!
|
||||
"Array that has length of 13. 0 index = null. Other indexes correspond months e.g. index 1 = January."
|
||||
TC: [Int]!
|
||||
"Array that has length of 13. 0 index = null. Other indexes correspond months e.g. index 1 = January."
|
||||
RM: [Int]!
|
||||
"Array that has length of 13. 0 index = null. Other indexes correspond months e.g. index 1 = January."
|
||||
CB: [Int]!
|
||||
}
|
||||
type Trend {
|
||||
weapon: String!
|
||||
counts: [Year!]!
|
||||
}
|
||||
`
|
||||
|
||||
const resolvers = {
|
||||
Query: {
|
||||
searchForTrend: (root, args) => {
|
||||
return Trend
|
||||
.findOne({ weapon: args.weapon })
|
||||
.catch(e => {
|
||||
throw new UserInputError(e.message, {
|
||||
invalidArgs: args,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Trend: typeDef,
|
||||
trendResolvers: resolvers
|
||||
}
|
||||
1
scripts/WeaponInfo_Main_5_0.json
Normal file
57
scripts/generate_weapon_info.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import json
|
||||
|
||||
weapons = ["Sploosh-o-matic", "Neo Sploosh-o-matic", "Sploosh-o-matic 7",
|
||||
"Splattershot Jr.", "Custom Splattershot Jr.", "Kensa Splattershot Jr.",
|
||||
"Splash-o-matic", "Neo Splash-o-matic", "Aerospray MG", "Aerospray RG",
|
||||
"Aerospray PG", "Splattershot", "Tentatek Splattershot", "Kensa Splattershot",
|
||||
".52 Gal", ".52 Gal Deco", "Kensa .52 Gal", "N-ZAP '85", "N-ZAP '89",
|
||||
"N-ZAP '83", "Splattershot Pro", "Forge Splattershot Pro", "Kensa Splattershot Pro",
|
||||
".96 Gal", ".96 Gal Deco", "Jet Squelcher", "Custom Jet Squelcher",
|
||||
"L-3 Nozzlenose", "L-3 Nozzlenose D", "Kensa L-3 Nozzlenose",
|
||||
"H-3 Nozzlenose", "H-3 Nozzlenose D", "Cherry H-3 Nozzlenose", "Squeezer",
|
||||
"Foil Squeezer",
|
||||
"Luna Blaster", "Luna Blaster Neo", "Kensa Luna Blaster",
|
||||
"Blaster", "Custom Blaster", "Range Blaster", "Custom Range Blaster",
|
||||
"Grim Range Blaster", "Rapid Blaster", "Rapid Blaster Deco", "Kensa Rapid Blaster",
|
||||
"Rapid Blaster Pro", "Rapid Blaster Pro Deco", "Clash Blaster", "Clash Blaster Neo",
|
||||
"Carbon Roller", "Carbon Roller Deco", "Splat Roller", "Krak-On Splat Roller",
|
||||
"Kensa Splat Roller", "Dynamo Roller", "Gold Dynamo Roller", "Kensa Dynamo Roller",
|
||||
"Flingza Roller", "Foil Flingza Roller", "Inkbrush", "Inkbrush Nouveau",
|
||||
"Permanent Inkbrush", "Octobrush", "Octobrush Nouveau", "Kensa Octobrush",
|
||||
"Classic Squiffer", "New Squiffer", "Fresh Squiffer", "Splat Charger",
|
||||
"Firefin Splat Charger", "Kensa Charger", "Splatterscope", "Firefin Splatterscope",
|
||||
"Kensa Splatterscope", "E-liter 4K", "Custom E-liter 4K", "E-liter 4K Scope",
|
||||
"Custom E-liter 4K Scope", "Bamboozler 14 Mk I", "Bamboozler 14 Mk II",
|
||||
"Bamboozler 14 Mk III", "Goo Tuber", "Custom Goo Tuber", "Slosher", "Slosher Deco", "Soda Slosher", "Tri-Slosher",
|
||||
"Tri-Slosher Nouveau", "Sloshing Machine", "Sloshing Machine Neo",
|
||||
"Kensa Sloshing Machine", "Bloblobber", "Bloblobber Deco", "Explosher",
|
||||
"Custom Explosher", "Mini Splatling", "Zink Mini Splatling", "Kensa Mini Splatling",
|
||||
"Heavy Splatling", "Heavy Splatling Deco", "Heavy Splatling Remix",
|
||||
"Hydra Splatling", "Custom Hydra Splatling", "Ballpoint Splatling",
|
||||
"Ballpoint Splatling Nouveau", "Nautilus 47", "Nautilus 79",
|
||||
"Dapple Dualies", "Dapple Dualies Nouveau", "Clear Dapple Dualies",
|
||||
"Splat Dualies", "Enperry Splat Dualies", "Kensa Splat Dualies", "Glooga Dualies",
|
||||
"Glooga Dualies Deco", "Kensa Glooga Dualies", "Dualie Squelchers",
|
||||
"Custom Dualie Squelchers", "Dark Tetra Dualies", "Light Tetra Dualies",
|
||||
"Splat Brella", "Sorella Brella", "Tenta Brella", "Tenta Sorella Brella",
|
||||
"Tenta Camo Brella", "Undercover Brella", "Undercover Sorella Brella", "Kensa Undercover Brella"]
|
||||
|
||||
weapon_info = {}
|
||||
|
||||
lang_dict = json.loads(open('lang_dict_EUen.json').read())
|
||||
wpn_list = json.loads(open('WeaponInfo_Main_5_0.json').read())
|
||||
|
||||
for wpn_obj in wpn_list:
|
||||
Name = lang_dict[wpn_obj['Name']].strip()
|
||||
if Name not in weapons:
|
||||
print(Name)
|
||||
continue
|
||||
Sub = lang_dict[wpn_obj['Sub']]
|
||||
Special = lang_dict[wpn_obj['Special']]
|
||||
Range = wpn_obj['Range']
|
||||
SpecialCost = wpn_obj['SpecialCost']
|
||||
weapon_info[Name] = {"Sub": Sub, "Special": Special, "Range": Range, "SpecialCost": SpecialCost}
|
||||
|
||||
with open('weapon_info.json', 'w') as fp:
|
||||
json.dump(weapon_info, fp)
|
||||
|
||||
1
scripts/lang_dict_EUen.json
Normal file
56
scripts/placements_to_trends.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from config import uri
|
||||
import pymongo
|
||||
import json
|
||||
|
||||
def main():
|
||||
client = pymongo.MongoClient(uri)
|
||||
db = client.production
|
||||
placements = db.placements.find({ })
|
||||
wpn_dict = json.loads(open('weapon_info.json').read())
|
||||
|
||||
trends = {}
|
||||
modes = {1: "SZ", 2: "TC", 3: "RM", 4: "CB"}
|
||||
for p in placements:
|
||||
year = p['year']
|
||||
weapon = p['weapon']
|
||||
mode = modes[p['mode']]
|
||||
month = p['month']
|
||||
weapon_obj = trends.get(weapon, {})
|
||||
year_obj = weapon_obj.get(year, {"SZ": [None,0,0,0,0,0,0,0,0,0,0,0,0], "TC": [None,0,0,0,0,0,0,0,0,0,0,0,0], "RM": [None,0,0,0,0,0,0,0,0,0,0,0,0], "CB": [None,0,0,0,0,0,0,0,0,0,0,0,0]})
|
||||
year_obj[mode][month] = year_obj[mode][month] + 1
|
||||
weapon_obj[year] = year_obj
|
||||
trends[weapon] = weapon_obj
|
||||
|
||||
sub = wpn_dict[weapon]["Sub"]
|
||||
special = wpn_dict[weapon]["Special"]
|
||||
|
||||
weapon_obj = trends.get(sub, {})
|
||||
year_obj = weapon_obj.get(year, {"SZ": [None,0,0,0,0,0,0,0,0,0,0,0,0], "TC": [None,0,0,0,0,0,0,0,0,0,0,0,0], "RM": [None,0,0,0,0,0,0,0,0,0,0,0,0], "CB": [None,0,0,0,0,0,0,0,0,0,0,0,0]})
|
||||
year_obj[mode][month] = year_obj[mode][month] + 1
|
||||
weapon_obj[year] = year_obj
|
||||
trends[sub] = weapon_obj
|
||||
|
||||
weapon_obj = trends.get(special, {})
|
||||
year_obj = weapon_obj.get(year, {"SZ": [None,0,0,0,0,0,0,0,0,0,0,0,0], "TC": [None,0,0,0,0,0,0,0,0,0,0,0,0], "RM": [None,0,0,0,0,0,0,0,0,0,0,0,0], "CB": [None,0,0,0,0,0,0,0,0,0,0,0,0]})
|
||||
year_obj[mode][month] = year_obj[mode][month] + 1
|
||||
weapon_obj[year] = year_obj
|
||||
trends[special] = weapon_obj
|
||||
|
||||
to_bulk_add = []
|
||||
|
||||
for key in trends:
|
||||
trend_obj = {"weapon": key, "counts": []}
|
||||
for i in range(2018, 2024):
|
||||
if i in trends[key]:
|
||||
modes_obj = trends[key][i]
|
||||
modes_obj["year"] = i
|
||||
trend_obj['counts'].append(modes_obj)
|
||||
to_bulk_add.append(trend_obj)
|
||||
|
||||
db.trends.insert_many(to_bulk_add)
|
||||
print("done")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||