build collection

This commit is contained in:
Sendou 2019-06-14 13:01:51 +03:00
parent 4ed8cd2ae6
commit 7481d1c8ee
32 changed files with 754 additions and 783 deletions

View File

@ -1,13 +1,13 @@
{
"files": {
"main.js": "/static/js/main.11805f7e.chunk.js",
"main.js.map": "/static/js/main.11805f7e.chunk.js.map",
"main.js": "/static/js/main.ba99c69a.chunk.js",
"main.js.map": "/static/js/main.ba99c69a.chunk.js.map",
"runtime~main.js": "/static/js/runtime~main.a8a9905a.js",
"runtime~main.js.map": "/static/js/runtime~main.a8a9905a.js.map",
"static/js/2.8f79602a.chunk.js": "/static/js/2.8f79602a.chunk.js",
"static/js/2.8f79602a.chunk.js.map": "/static/js/2.8f79602a.chunk.js.map",
"static/js/2.18546bdc.chunk.js": "/static/js/2.18546bdc.chunk.js",
"static/js/2.18546bdc.chunk.js.map": "/static/js/2.18546bdc.chunk.js.map",
"index.html": "/index.html",
"precache-manifest.57456dced1c66d79720b9e84938825c8.js": "/precache-manifest.57456dced1c66d79720b9e84938825c8.js",
"precache-manifest.bed1d8e4606fb4bd4bb8b0aa9d016cd4.js": "/precache-manifest.bed1d8e4606fb4bd4bb8b0aa9d016cd4.js",
"service-worker.js": "/service-worker.js",
"static/media/ancho-v_games.png": "/static/media/ancho-v_games.07d5d0f6.png",
"static/media/arowana_mall.png": "/static/media/arowana_mall.26cf0823.png",

View File

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><link rel="stylesheet" href="//cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><title>sendou.ink</title></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(l){function e(e){for(var r,t,n=e[0],o=e[1],u=e[2],f=0,i=[];f<n.length;f++)t=n[f],p[t]&&i.push(p[t][0]),p[t]=0;for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(l[r]=o[r]);for(s&&s(e);i.length;)i.shift()();return c.push.apply(c,u||[]),a()}function a(){for(var e,r=0;r<c.length;r++){for(var t=c[r],n=!0,o=1;o<t.length;o++){var u=t[o];0!==p[u]&&(n=!1)}n&&(c.splice(r--,1),e=f(f.s=t[0]))}return e}var t={},p={1:0},c=[];function f(e){if(t[e])return t[e].exports;var r=t[e]={i:e,l:!1,exports:{}};return l[e].call(r.exports,r,r.exports,f),r.l=!0,r.exports}f.m=l,f.c=t,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(r,e){if(1&e&&(r=f(r)),8&e)return r;if(4&e&&"object"==typeof r&&r&&r.__esModule)return r;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:r}),2&e&&"string"!=typeof r)for(var n in r)f.d(t,n,function(e){return r[e]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="/";var r=window.webpackJsonp=window.webpackJsonp||[],n=r.push.bind(r);r.push=e,r=r.slice();for(var o=0;o<r.length;o++)e(r[o]);var s=n;a()}([])</script><script src="/static/js/2.8f79602a.chunk.js"></script><script src="/static/js/main.11805f7e.chunk.js"></script></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><link rel="stylesheet" href="//cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><title>sendou.ink</title></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(l){function e(e){for(var r,t,n=e[0],o=e[1],u=e[2],f=0,i=[];f<n.length;f++)t=n[f],p[t]&&i.push(p[t][0]),p[t]=0;for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(l[r]=o[r]);for(s&&s(e);i.length;)i.shift()();return c.push.apply(c,u||[]),a()}function a(){for(var e,r=0;r<c.length;r++){for(var t=c[r],n=!0,o=1;o<t.length;o++){var u=t[o];0!==p[u]&&(n=!1)}n&&(c.splice(r--,1),e=f(f.s=t[0]))}return e}var t={},p={1:0},c=[];function f(e){if(t[e])return t[e].exports;var r=t[e]={i:e,l:!1,exports:{}};return l[e].call(r.exports,r,r.exports,f),r.l=!0,r.exports}f.m=l,f.c=t,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(r,e){if(1&e&&(r=f(r)),8&e)return r;if(4&e&&"object"==typeof r&&r&&r.__esModule)return r;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:r}),2&e&&"string"!=typeof r)for(var n in r)f.d(t,n,function(e){return r[e]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="/";var r=window.webpackJsonp=window.webpackJsonp||[],n=r.push.bind(r);r.push=e,r=r.slice();for(var o=0;o<r.length;o++)e(r[o]);var s=n;a()}([])</script><script src="/static/js/2.18546bdc.chunk.js"></script><script src="/static/js/main.ba99c69a.chunk.js"></script></body></html>

View File

@ -1,15 +1,15 @@
self.__precacheManifest = (self.__precacheManifest || []).concat([
{
"revision": "71842041eea18563ab917159b1dbf3b8",
"revision": "014577c816883db02635839c8a9e172a",
"url": "/index.html"
},
{
"revision": "834d30fd9e3e84494043",
"url": "/static/js/2.8f79602a.chunk.js"
"revision": "b867ef14ecdd9a6e5652",
"url": "/static/js/2.18546bdc.chunk.js"
},
{
"revision": "3198713366d488e35a2e",
"url": "/static/js/main.11805f7e.chunk.js"
"revision": "56bdde670711d2085094",
"url": "/static/js/main.ba99c69a.chunk.js"
},
{
"revision": "42ac5946195a7306e2a5",

View File

@ -14,7 +14,7 @@
importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.0/workbox-sw.js");
importScripts(
"/precache-manifest.57456dced1c66d79720b9e84938825c8.js"
"/precache-manifest.bed1d8e4606fb4bd4bb8b0aa9d016cd4.js"
);
self.addEventListener('message', (event) => {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -81,6 +81,7 @@ const typeDefs = gql`
unique_id: String!
alias: String
twitter: String
discord_id: String
weapons: [String!]!
weaponsCount: Int!
topTotal: [Placement!]!
@ -187,6 +188,12 @@ const typeDefs = gql`
clothing: [Ability!]!
shoes: [Ability!]!
createdAt: String
top: Boolean!
discord_user: User!
}
type BuildCollection {
builds: [Build]!
pageCount: Int!
}
type Query {
playerCount: Int!
@ -210,6 +217,7 @@ const typeDefs = gql`
user: User
searchForUser(discord_id: String twitter: String): User
searchForBuilds(discord_id: String!): [Build]!
searchForBuildsByWeapon(weapon: String! page: Int): BuildCollection!
deleteBuild(id: ID!): Boolean
}
type Mutation {
@ -549,13 +557,44 @@ const resolvers = {
},
searchForBuilds: (root, args) => {
return Build
.find( {discord_id: args.discord_id })
.find({ discord_id: args.discord_id })
.sort({'weapon': "asc"})
.catch(e => {
throw new UserInputError(e.message, {
invalidArgs, args,
invalidArgs: args,
})
})
},
searchForBuildsByWeapon: async (root, args) => {
const buildsPerPage = 20
const currentPage = args.page ? args.page - 1 : 0
const searchCriteria = { weapon: args.weapon }
const buildCount = await Build
.countDocuments(searchCriteria)
.catch(e => {
throw new UserInputError(e.message, {
invalidArgs: args,
})
})
const pageCount = Math.ceil(buildCount / buildsPerPage)
if (currentPage > pageCount) throw new UserInputError('too big page number given', {
invalidArgs: args,
})
const builds = await Build
.find(searchCriteria)
.skip(buildsPerPage * currentPage)
.limit(buildsPerPage)
.sort({'top': 'desc', 'updatedAt': 'desc'})
.populate('discord_user')
.catch(e => {
throw new UserInputError(e.message, {
invalidArgs: args,
})
})
return { builds, pageCount }
}
},
Mutation: {
@ -604,6 +643,59 @@ const resolvers = {
return true
}
},
Player: {
discord_id: async (root) => {
const user = await User
.findOne({ twitter_name: root.twitter })
.catch(e => {
throw new UserInputError, {
invalidArgs: args,
}
})
return user.discord_id
}
},
Build: {
top: async (root) => {
if (typeof root.top === 'boolean') return root.top
const user = await User
.findOne({ discord_id: root.discord_id })
.catch(e => {
throw new UserInputError, {
invalidArgs: args,
}
})
if (!user) throw new UserInputError
if (!user.twitter_name) {
await Build.findByIdAndUpdate(root._id, { top: false })
return false
}
const player = await Player
.findOne({ twitter: user.twitter_name })
.catch(e => {
throw new UserInputError, {
invalidArgs: args,
}
})
if (!player) { //twitter not set or played not in top 500
await Build.findByIdAndUpdate(root._id, { top: false })
return false
}
if (player.weapons.indexOf(root.weapon) >= 0) { //if player has reached top 500 with the weapon
await Build.findByIdAndUpdate(root._id, { top: true })
return true
}
await Build.findByIdAndUpdate(root._id, { top: false })
return false
}
}
}

View File

@ -6,7 +6,15 @@ const buildSchema = new mongoose.Schema({
title: {type: String},
headgear: {type: [String], required: true},
clothing: {type: [String], required: true},
shoes: {type: [String], required: true}
shoes: {type: [String], required: true},
top: {type: Boolean}
}, { timestamps: true })
buildSchema.virtual('discord_user', {
ref: 'User',
localField: 'discord_id',
foreignField: 'discord_id',
justOne: true
})
module.exports = mongoose.model('Build', buildSchema)

974
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -10,21 +10,21 @@
"author": "Sendou",
"license": "ISC",
"dependencies": {
"apollo-server": "^2.4.8",
"apollo-server-express": "^2.5.0",
"axios": "^0.18.0",
"apollo-server": "^2.6.3",
"apollo-server-express": "^2.6.3",
"axios": "^0.18.1",
"btoa": "^1.2.1",
"cors": "^2.8.5",
"dotenv": "^7.0.0",
"express-session": "^1.16.1",
"graphql": "^14.2.1",
"mongoose": "^5.5.5",
"express-session": "^1.16.2",
"graphql": "^14.3.1",
"mongoose": "^5.5.14",
"mongoose-unique-validator": "^2.0.3",
"node-fetch": "^2.6.0",
"passport": "^0.4.0",
"passport-discord": "^0.1.3"
},
"devDependencies": {
"nodemon": "^1.19.0"
"nodemon": "^1.19.1"
}
}

View File

@ -1526,6 +1526,14 @@
"@xtuc/long": "4.2.2"
}
},
"@wry/equality": {
"version": "0.1.9",
"resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.1.9.tgz",
"integrity": "sha512-mB6ceGjpMGz1ZTza8HYnrPGos2mC6So4NhS1PtZ8s4Qt0K7fBiIGhpSxUbQmhwcSWE3no+bYxmI2OL6KuXYmoQ==",
"requires": {
"tslib": "^1.9.3"
}
},
"@xtuc/ieee754": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
@ -3756,15 +3764,6 @@
"sha.js": "^2.4.8"
}
},
"create-react-context": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.2.3.tgz",
"integrity": "sha512-CQBmD0+QGgTaxDL3OX1IDXYqjkp2It4RIbcb99jS6AEg27Ga+a9G3JtK6SIu0HBwPLZlmwt9F7UwWA4Bn92Rag==",
"requires": {
"fbjs": "^0.8.0",
"gud": "^1.0.0"
}
},
"cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
@ -4456,14 +4455,6 @@
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
"encoding": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
"integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
"requires": {
"iconv-lite": "~0.4.13"
}
},
"end-of-stream": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
@ -5304,35 +5295,6 @@
"bser": "^2.0.0"
}
},
"fbjs": {
"version": "0.8.17",
"resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz",
"integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=",
"requires": {
"core-js": "^1.0.0",
"isomorphic-fetch": "^2.1.1",
"loose-envify": "^1.0.0",
"object-assign": "^4.1.0",
"promise": "^7.1.1",
"setimmediate": "^1.0.5",
"ua-parser-js": "^0.7.18"
},
"dependencies": {
"core-js": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
"integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
},
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
"requires": {
"asap": "~2.0.3"
}
}
}
},
"figgy-pudding": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz",
@ -5740,9 +5702,9 @@
"integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA=="
},
"graphql": {
"version": "14.2.1",
"resolved": "https://registry.npmjs.org/graphql/-/graphql-14.2.1.tgz",
"integrity": "sha512-2PL1UbvKeSjy/lUeJqHk+eR9CvuErXoCNwJI4jm3oNFEeY+9ELqHNKO1ZuSxAkasPkpWbmT/iMRMFxd3cEL3tQ==",
"version": "14.3.1",
"resolved": "https://registry.npmjs.org/graphql/-/graphql-14.3.1.tgz",
"integrity": "sha512-FZm7kAa3FqKdXy8YSSpAoTtyDFMIYSpCDOr+3EqlI1bxmtHu+Vv/I2vrSeT1sBOEnEniX3uo4wFhFdS/8XN6gA==",
"requires": {
"iterall": "^1.2.2"
}
@ -6580,15 +6542,6 @@
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
},
"isomorphic-fetch": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
"integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
"requires": {
"node-fetch": "^1.0.1",
"whatwg-fetch": ">=0.10.0"
}
},
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
@ -8258,6 +8211,16 @@
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
},
"mini-create-react-context": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz",
"integrity": "sha512-2v+OeetEyliMt5VHMXsBhABoJ0/M4RCe7fatd/fBy6SMiKazUSEt3gxxypfnk2SHMkdBYvorHRoQxuGoiwbzAw==",
"requires": {
"@babel/runtime": "^7.4.0",
"gud": "^1.0.0",
"tiny-warning": "^1.0.2"
}
},
"mini-css-extract-plugin": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz",
@ -8454,15 +8417,6 @@
"lower-case": "^1.1.1"
}
},
"node-fetch": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
"integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
"requires": {
"encoding": "^0.1.11",
"is-stream": "^1.0.1"
}
},
"node-forge": {
"version": "0.7.5",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz",
@ -10246,16 +10200,29 @@
}
},
"react-apollo": {
"version": "2.5.5",
"resolved": "https://registry.npmjs.org/react-apollo/-/react-apollo-2.5.5.tgz",
"integrity": "sha512-zoJYlkI3i7+f1ejCbFtWU2GLCxjrmB3Es6RANyEZcbl0yetf5TI6ofMjBzILTvwoqp6tiQHH/8q66vQF0KcLmQ==",
"version": "2.5.6",
"resolved": "https://registry.npmjs.org/react-apollo/-/react-apollo-2.5.6.tgz",
"integrity": "sha512-WWX5UykTtmW6+awjqEsSWSdvVyZv/vsavUgpdI4ddn4CBdz47INC+iTdJBnYaUFMB24GmqjFFSoSd98gu1xqKA==",
"requires": {
"apollo-utilities": "^1.2.1",
"apollo-utilities": "^1.3.0",
"hoist-non-react-statics": "^3.3.0",
"lodash.isequal": "^4.5.0",
"prop-types": "^15.7.2",
"ts-invariant": "^0.4.0",
"ts-invariant": "^0.4.2",
"tslib": "^1.9.3"
},
"dependencies": {
"apollo-utilities": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.3.2.tgz",
"integrity": "sha512-JWNHj8XChz7S4OZghV6yc9FNnzEXj285QYp/nLNh943iObycI5GTDO3NGR9Dth12LRrSFMeDOConPfPln+WGfg==",
"requires": {
"@wry/equality": "^0.1.2",
"fast-json-stable-stringify": "^2.0.0",
"ts-invariant": "^0.4.0",
"tslib": "^1.9.3"
}
}
}
},
"react-apollo-hooks": {
@ -10378,15 +10345,15 @@
"integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA=="
},
"react-router": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.0.0.tgz",
"integrity": "sha512-6EQDakGdLG/it2x9EaCt9ZpEEPxnd0OCLBHQ1AcITAAx7nCnyvnzf76jKWG1s2/oJ7SSviUgfWHofdYljFexsA==",
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.0.1.tgz",
"integrity": "sha512-EM7suCPNKb1NxcTZ2LEOWFtQBQRQXecLxVpdsP4DW4PbbqYWeRiLyV/Tt1SdCrvT2jcyXAXmVTmzvSzrPR63Bg==",
"requires": {
"@babel/runtime": "^7.1.2",
"create-react-context": "^0.2.2",
"history": "^4.9.0",
"hoist-non-react-statics": "^3.1.0",
"loose-envify": "^1.3.1",
"mini-create-react-context": "^0.3.0",
"path-to-regexp": "^1.7.0",
"prop-types": "^15.6.2",
"react-is": "^16.6.0",
@ -10410,15 +10377,15 @@
}
},
"react-router-dom": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.0.0.tgz",
"integrity": "sha512-wSpja5g9kh5dIteZT3tUoggjnsa+TPFHSMrpHXMpFsaHhQkm/JNVGh2jiF9Dkh4+duj4MKCkwO6H08u6inZYgQ==",
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.0.1.tgz",
"integrity": "sha512-zaVHSy7NN0G91/Bz9GD4owex5+eop+KvgbxXsP/O+iW1/Ln+BrJ8QiIR5a6xNPtrdTvLkxqlDClx13QO1uB8CA==",
"requires": {
"@babel/runtime": "^7.1.2",
"history": "^4.9.0",
"loose-envify": "^1.3.1",
"prop-types": "^15.6.2",
"react-router": "5.0.0",
"react-router": "5.0.1",
"tiny-invariant": "^1.0.2",
"tiny-warning": "^1.0.0"
}
@ -12021,9 +11988,9 @@
"integrity": "sha512-fwkLWH+DimvA4YCy+/nvJd61nWQQ2liO/nF/RjkTpiOGi+zxZzVkhb1mvbHIIW4b/8nDsYI8uTmAlc0nNkRMOw=="
},
"ts-invariant": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.4.1.tgz",
"integrity": "sha512-fdL8AZinDiVKMsOI0cOWHLprS85LWy2p/eVSctVe6fpZF9BAvO59sQYMEWQ37yybBtlKU2zkmILYmy1jrOf6+g==",
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.4.4.tgz",
"integrity": "sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA==",
"requires": {
"tslib": "^1.9.3"
}
@ -12086,11 +12053,6 @@
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
"ua-parser-js": {
"version": "0.7.19",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.19.tgz",
"integrity": "sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ=="
},
"uglify-js": {
"version": "3.4.10",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz",

View File

@ -6,13 +6,13 @@
"apollo-boost": "^0.3.1",
"apollo-link": "^1.2.11",
"apollo-link-context": "^1.0.17",
"graphql": "^14.2.1",
"graphql": "^14.3.1",
"react": "^16.8.6",
"react-apollo": "^2.5.5",
"react-apollo": "^2.5.6",
"react-apollo-hooks": "^0.4.5",
"react-dom": "^16.8.6",
"react-router": "^5.0.0",
"react-router-dom": "^5.0.0",
"react-router": "^5.0.1",
"react-router-dom": "^5.0.1",
"react-scripts": "3.0.0",
"semantic-ui-react": "^0.86.0"
},

10
react-ui/src/App.js vendored
View File

@ -15,6 +15,7 @@ import Rotations from './components/Tools/Rotations'
import Links from './components/Misc/Links'
import UserPage from './components/SoloLadder/UserPage'
import HomePage from './components/Misc/HomePage'
import BuildSearch from './components/SoloLadder/BuildSearch'
const App = () => {
const [menuSelection, setMenuSelection] = useState('home')
@ -47,6 +48,15 @@ const App = () => {
<Route exact path="/u/:user" render={({ match }) =>
<UserPage userIdOrName={match.params.user}/>
} />
<Route exact path="/builds" render={() =>
<BuildSearch setMenuSelection={setMenuSelection} />
} />
<Route exact path="/builds/:weapon" render={({ match }) =>
<BuildSearch
setMenuSelection={setMenuSelection}
weaponFromUrl={match.params.weapon.replace(/_/g, ' ')}
/>
} />
<Route path="/404" render={() => <NotFound />} />
<Route path="*" render={() => <NotFound />} />
</Switch>

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'
import React from 'react'
import { Menu, Segment, Button, Image, Dropdown } from 'semantic-ui-react'
import { useQuery } from 'react-apollo-hooks'
import { userLean } from '../../graphql/queries/userLean'
@ -6,7 +6,6 @@ import { withRouter, Link } from 'react-router-dom'
import { memCakes } from '../../utils/lists'
const MainMenu = withRouter(({ history, menuSelection, setMenuSelection }) => {
const [memCakePic, setMemCakePic] = useState(memCakes[Math.floor(Math.random()*memCakes.length)])
const { data, error, loading } = useQuery(userLean)
const logIn = () => {
@ -55,6 +54,8 @@ const MainMenu = withRouter(({ history, menuSelection, setMenuSelection }) => {
)
}
const memCakePic = memCakes[Math.floor(Math.random()*memCakes.length)]
return (
<Segment inverted>
<Menu inverted secondary stackable>
@ -76,6 +77,14 @@ const MainMenu = withRouter(({ history, menuSelection, setMenuSelection }) => {
setMenuSelection('rotations')
}}
/>
<Menu.Item
name='builds'
active={menuSelection === 'builds'}
onClick={() => {
history.push('/builds')
setMenuSelection('builds')
}}
/>
<Menu.Item
name='leaderboards'
active={menuSelection === 'leaderboards'}

View File

@ -31,7 +31,7 @@ import OS from '../img/abilityIcons/OS.png'
import EMPTY from '../img/abilityIcons/EMPTY.png'
const Build = ({ build, existingAbilities, setAbilities, removeBuildFunction }) => {
const lineStyle = {
"display": "inline-block",
"width": "2px",
@ -116,9 +116,6 @@ const Build = ({ build, existingAbilities, setAbilities, removeBuildFunction })
}
const buildTitle = !build.title || build.title === "" ? `${build.weapon} Build` : build.title
console.log('removeBuildFunction', removeBuildFunction)
console.log('!removeBuildFunction', !removeBuildFunction)
return (
<div>

View File

@ -0,0 +1,164 @@
import React, { useState } from 'react'
import { useQuery } from 'react-apollo-hooks'
import { Table, Loader, Image, Pagination, Header, Popup, Icon } from 'semantic-ui-react'
import { Link, Redirect } from 'react-router-dom'
import { searchForBuildsByWeapon } from '../../graphql/queries/searchForBuildsByWeapon'
import weaponDict from '../../utils/english_internal.json'
import top500 from '../img/misc/top500.png'
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'
const abilities = {
"BDU": {image: BDU, fullName: "Bomb Defense Up DX"},
"BRU": {image: BRU, fullName: "Sub Power Up"},
"CB": {image: CB, fullName: "Comeback", mainOnly: true},
"DR": {image: DR, fullName: "Drop Roller", mainOnly: true},
"H": {image: H, fullName: "Haunt", mainOnly: true},
"ISM": {image: ISM, fullName: "Ink Saver (Main)"},
"ISS": {image: ISS, fullName: "Ink Saver (Sub)"},
"LDE": {image: LDE, fullName: "Last-Ditch Effort", mainOnly: true},
"MPU": {image: MPU, fullName: "Main Power Up"},
"NS": {image: NS, fullName: "Ninja Squid", mainOnly: true},
"OG": {image: OG, fullName: "Opening Gambit", mainOnly: true},
"QR": {image: QR, fullName: "Quick Respawn"},
"QSJ": {image: QSJ, fullName: "Quick Super Jump"},
"REC": {image: REC, fullName: "Ink Recovery Up"},
"RES": {image: RES, fullName: "Ink Resistance Up"},
"RP": {image: RP, fullName: "Respawn Punisher", mainOnly: true},
"RSU": {image: RSU, fullName: "Run Speed Up"},
"SCU": {image: SCU, fullName: "Special Charge Up"},
"SJ": {image: SJ, fullName: "Stealth Jump", mainOnly: true},
"SPU": {image: SPU, fullName: "Special Power Up"},
"SS": {image: SS, fullName: "Special Saver"},
"SSU": {image: SSU, fullName: "Swim Speed Up"},
"T": {image: T, fullName: "Tenacity", mainOnly: true},
"TI": {image: TI, fullName: "Thermal Ink", mainOnly: true},
"OS": {image: OS, fullName: "Object Shredder", mainOnly: true}
}
const BuildCollection = ({ weapon }) => {
const [page, setPage] = useState(1)
const { data, error, loading } = useQuery(searchForBuildsByWeapon, { variables: { weapon, page }})
if (loading) {
return <div style={{"paddingTop": "25px", "paddingBottom": "20000px"}} ><Loader active inline='centered' /></div>
}
if (error) {
return <div style={{"color": "red"}}>{error.message}</div>
}
const builds = data.searchForBuildsByWeapon.builds
if (!builds) return <Redirect to='/404' />
if (builds.length === 0) return <div style={{'paddingTop': '10px'}}>No builds with this weapon yet. You can be the first to submit one!</div>
return (
<div>
<div style={{'paddingTop': '10px'}}>
<Header size='large'>
<img
src={`https://raw.githubusercontent.com/Leanny/leanny.github.io/master/splat2/weapons/Wst_${weaponDict[weapon]}.png`}
alt={weapon}
/> {weapon} Builds
</Header>
<Header size='tiny'></Header>
</div>
<div>
<Table celled padded>
<Table.Header>
<Table.Row>
<Table.HeaderCell>Discord Tag</Table.HeaderCell>
<Table.HeaderCell textAlign='center'>
<Popup
trigger={<Icon name='question circle'/>}
content='If the player who posted the build has placed Top 500 in X Rank with the weapon in question Top 500 crown is displayed in this column.'
position='top center'
/>
</Table.HeaderCell>
<Table.HeaderCell>Headgear</Table.HeaderCell>
<Table.HeaderCell>Clothing</Table.HeaderCell>
<Table.HeaderCell>Shoes</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
{builds.map(b => {
return (
<Table.Row key={b.id}>
<Table.Cell>
<Link to={`/u/${b.discord_id}`}>{`${b.discord_user.username}#${b.discord_user.discriminator}`}</Link>
</Table.Cell>
<Table.Cell collapsing>
{b.top ? <Image src={top500} style={{ "maxWidth": "40px", "height": "auto" }} /> : null}
</Table.Cell>
<Table.Cell singleLine>
<Image src={abilities[b.headgear[0]].image} inline />
<Image src={abilities[b.headgear[1]].image} style={{ "maxWidth": "40px", "height": "auto" }} inline />
<Image src={abilities[b.headgear[2]].image} style={{ "maxWidth": "40px", "height": "auto" }} inline />
<Image src={abilities[b.headgear[3]].image} style={{ "maxWidth": "40px", "height": "auto" }} inline />
</Table.Cell>
<Table.Cell singleLine>
<Image src={abilities[b.clothing[0]].image} inline />
<Image src={abilities[b.clothing[1]].image} style={{ "maxWidth": "40px", "height": "auto" }} inline />
<Image src={abilities[b.clothing[2]].image} style={{ "maxWidth": "40px", "height": "auto" }} inline />
<Image src={abilities[b.clothing[3]].image} style={{ "maxWidth": "40px", "height": "auto" }} inline />
</Table.Cell>
<Table.Cell singleLine>
<Image src={abilities[b.shoes[0]].image} inline />
<Image src={abilities[b.shoes[1]].image} style={{ "maxWidth": "40px", "height": "auto" }} inline />
<Image src={abilities[b.shoes[2]].image} style={{ "maxWidth": "40px", "height": "auto" }} inline />
<Image src={abilities[b.shoes[3]].image} style={{ "maxWidth": "40px", "height": "auto" }} inline />
</Table.Cell>
</Table.Row>
)
})}
</Table.Body>
</Table>
<div>
{data.searchForBuildsByWeapon.pageCount > 1 ?
<Pagination
activePage={page}
boundaryRange={0}
onPageChange={(e, { activePage }) => {
window.scrollTo(0, 0)
setPage(activePage)}}
ellipsisItem={null}
firstItem={null}
lastItem={null}
siblingRange={1}
totalPages={data.searchForBuildsByWeapon.pageCount}
/> : null}
</div>
</div>
</div>
)
}
export default BuildCollection

View File

@ -52,7 +52,7 @@ const BuildForm = ({ addBuild, setShowForm, setSuccessMsg }) => {
return (
<div>
<div>
<Build build={build} existingAbilities={abilities} setAbilities={setAbilities}/>
<Build build={build} existingAbilities={abilities} setAbilities={setAbilities} />
</div>
<div style={{"paddingTop": "15px"}}>
<WeaponForm weaponForm={weaponForm} setWeaponForm={setWeaponForm} showImages={false} />

View File

@ -0,0 +1,25 @@
import React, { useState, useEffect } from 'react'
import WeaponForm from '../XSearch/WeaponForm'
import BuildCollection from './BuildCollection'
const BuildSearch = ({ setMenuSelection, weaponFromUrl }) => {
const [weapon, setWeapon] = useState(weaponFromUrl ? weaponFromUrl : '')
useEffect(() => {
setMenuSelection('builds')
document.title = "Builds - sendou.ink"
}, [setMenuSelection])
return (
<div>
<div>
<WeaponForm weaponForm={weapon} setWeaponForm={setWeapon} push />
</div>
<div>
{weapon === '' ? null : <BuildCollection weapon={weapon}/>}
</div>
</div>
)
}
export default BuildSearch

View File

@ -1,6 +1,6 @@
import React, { useState } from 'react'
import { useQuery, useMutation } from 'react-apollo-hooks'
import { Button, Loader, Message, Popup } from 'semantic-ui-react'
import { Button, Loader, Message } from 'semantic-ui-react'
import { addBuild } from '../../graphql/mutations/addBuild'
import { searchForBuilds } from '../../graphql/queries/searchForBuilds'
@ -13,7 +13,6 @@ const BuildTab = ({ user, userViewed }) => {
const [ errorMsg, setErrorMsg ] = useState(null)
const [ successMsg, setSuccessMsg ] = useState(null)
const [ showForm, setShowForm ] = useState(false)
const [ deleteConfirm, setDeleteConfirm ] = useState(false)
const handleError = (error) => {
errorMsg(error.graphQLErrors[0].message)
@ -39,7 +38,6 @@ const BuildTab = ({ user, userViewed }) => {
const buildTitle = title ? title : `${weapon} build`
setDeleteConfirm(false)
setSuccessMsg(`Succesfully deleted ${buildTitle}`)
setTimeout(() => { setSuccessMsg(null) }, 10000)
}
@ -74,7 +72,7 @@ const BuildTab = ({ user, userViewed }) => {
<div style={{"paddingTop": "10px"}}>
{data.searchForBuilds.map(b =>
<div key={b.id} style={{"paddingTop": "10px"}}>
<Build build={b} removeBuildFunction={removeBuildFunction} />
<Build build={b} removeBuildFunction={removeBuildFunction} setSuccessMsg={setSuccessMsg} />
</div>)}
{data.searchForBuilds.length === 0 ? 'So far this user has no builds!' : null}
</div>

View File

@ -1,6 +1,7 @@
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 { playerInfo } from '../../graphql/queries/playerInfo'
import TopPlacementTable from './TopPlacementsTable'
@ -89,6 +90,7 @@ const InfoPlayer = ({ uid, setMenuSelection, twitter }) => {
{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}

View File

@ -4,7 +4,7 @@ import { withRouter } from 'react-router-dom'
import { weapons } from '../../utils/lists'
import weaponDict from '../../utils/english_internal.json'
const WeaponForm = ({ weaponForm, setWeaponForm, showImages=true }) => {
const WeaponForm = withRouter(({ history, weaponForm, setWeaponForm, showImages=true, push=false }) => {
return (
<div>
<Dropdown
@ -22,12 +22,15 @@ const WeaponForm = ({ weaponForm, setWeaponForm, showImages=true }) => {
)
)
}
onChange={(event, { value }) => setWeaponForm(value)}
onChange={(event, { value }) => {
setWeaponForm(value)
if (push) history.push(`/builds/${value.replace(/ /g, '_')}`)
}}
value={weaponForm}
/>
</div>
)
}
})
export const WeaponFormWithButton = withRouter(({ history }) => {
const [weaponForm, setWeaponForm] = useState('')

Binary file not shown.

After

Width:  |  Height:  |  Size: 1011 B

View File

@ -8,6 +8,7 @@ query playerInfo($uid: String, $twitter: String) {
weapons
alias
twitter
discord_id
topTotalScore
topShooterScore
topBlasterScore

View File

@ -10,6 +10,7 @@ query searchForBuilds($discord_id: String!) {
clothing
shoes
createdAt
top
}
}
`

View File

@ -0,0 +1,21 @@
import { gql } from 'apollo-boost'
export const searchForBuildsByWeapon = gql`
query searchForBuildsByWeapon($weapon: String!, $page: Int) {
searchForBuildsByWeapon(weapon: $weapon, page: $page) {
builds {
id
discord_id
top
headgear
clothing
shoes
discord_user {
username
discriminator
}
}
pageCount
}
}
`

View File

@ -1,7 +1,7 @@
import { gql } from 'apollo-boost'
export const searchForUser = gql`
query searchForUser($discord_id: String!) {
query searchForUser($discord_id: String) {
searchForUser(discord_id: $discord_id) {
username
discriminator