Merge pull request #15 from nikolabjelo/master

Huge backend modification with a lot of breaking changes
This commit is contained in:
Luis Fernando Molina authored and GitHub committed 2018-11-08 07:46:12 +01:00
commit ca15873568
90 files changed
+2671 -1517

No files matched your search

+23
View File
@@ -0,0 +1,23 @@
module.exports = {
parser: 'babel-eslint',
extends: [
'airbnb-base',
'plugin:react/recommended',
],
rules: {
'max-len': ['error', 140, 2],
'no-underscore-dangle': 'off',
'no-param-reassign': 'off',
'react/prop-types': 0,
'react/jsx-indent': ['error', 2],
},
settings: {
'react': {
'pragma': 'React',
'version': '16.5',
},
},
env: {
'browser': true,
},
};
+264 -62
View File
@@ -227,9 +227,9 @@
"integrity": "sha512-te5lMAWii1uEJ4FwLjzdlbw3+n0FZNOvFXHxQDKeT0dilh7HOzdMzV2TrJVUzq8ep7J4Na8OUYPRLSQkJHAlrg=="
},
"acorn": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.2.tgz",
"integrity": "sha512-GXmKIvbrN3TV7aVqAzVFaMW8F8wzVX7voEBRO3bDA64+EX37YSayggRJP5Xig6HYHBkWKpFg9W5gg6orklubhg==",
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.4.tgz",
"integrity": "sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg==",
"dev": true
},
"acorn-jsx": {
@@ -239,9 +239,9 @@
"dev": true
},
"ajv": {
"version": "6.5.4",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.4.tgz",
"integrity": "sha512-4Wyjt8+t6YszqaXnLDfMmG/8AlO5Zbcsy3ATHncCzjW/NoPzAId8AK6749Ybjmdt+kUY1gP60fCu46oDxPv/mg==",
"version": "6.5.5",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz",
"integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==",
"dev": true,
"requires": {
"fast-deep-equal": "^2.0.1",
@@ -263,9 +263,9 @@
"dev": true
},
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
"dev": true
},
"ansi-styles": {
@@ -381,6 +381,12 @@
"js-tokens": "^3.0.2"
},
"dependencies": {
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true
},
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
@@ -437,6 +443,27 @@
"eslint-visitor-keys": "^1.0.0"
}
},
"babel-runtime": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
"requires": {
"core-js": "^2.4.0",
"regenerator-runtime": "^0.11.0"
},
"dependencies": {
"core-js": {
"version": "2.5.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
"integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
},
"regenerator-runtime": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
}
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@@ -496,9 +523,9 @@
"integrity": "sha1-6LL+PX8at9aaMhma/5HqaTFAlRU="
},
"chardet": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
"dev": true
},
"circular-json": {
@@ -730,16 +757,16 @@
"dev": true
},
"eslint": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-5.4.0.tgz",
"integrity": "sha512-UIpL91XGex3qtL6qwyCQJar2j3osKxK9e3ano3OcGEIRM4oWIpCkDg9x95AXEC2wMs7PnxzOkPZ2gq+tsMS9yg==",
"version": "5.8.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-5.8.0.tgz",
"integrity": "sha512-Zok6Bru3y2JprqTNm14mgQ15YQu/SMDkWdnmHfFg770DIUlmMFd/gqqzCHekxzjHZJxXv3tmTpH0C1icaYJsRQ==",
"dev": true,
"requires": {
"ajv": "^6.5.0",
"babel-code-frame": "^6.26.0",
"@babel/code-frame": "^7.0.0",
"ajv": "^6.5.3",
"chalk": "^2.1.0",
"cross-spawn": "^6.0.5",
"debug": "^3.1.0",
"debug": "^4.0.1",
"doctrine": "^2.1.0",
"eslint-scope": "^4.0.0",
"eslint-utils": "^1.3.1",
@@ -751,11 +778,11 @@
"functional-red-black-tree": "^1.0.1",
"glob": "^7.1.2",
"globals": "^11.7.0",
"ignore": "^4.0.2",
"ignore": "^4.0.6",
"imurmurhash": "^0.1.4",
"inquirer": "^5.2.0",
"inquirer": "^6.1.0",
"is-resolvable": "^1.1.0",
"js-yaml": "^3.11.0",
"js-yaml": "^3.12.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.3.0",
"lodash": "^4.17.5",
@@ -766,15 +793,24 @@
"path-is-inside": "^1.0.2",
"pluralize": "^7.0.0",
"progress": "^2.0.0",
"regexpp": "^2.0.0",
"regexpp": "^2.0.1",
"require-uncached": "^1.0.3",
"semver": "^5.5.0",
"semver": "^5.5.1",
"strip-ansi": "^4.0.0",
"strip-json-comments": "^2.0.1",
"table": "^4.0.3",
"table": "^5.0.2",
"text-table": "^0.2.0"
},
"dependencies": {
"debug": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz",
"integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
},
"eslint-scope": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz",
@@ -787,6 +823,17 @@
}
}
},
"eslint-config-airbnb-base": {
"version": "13.1.0",
"resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz",
"integrity": "sha512-XWwQtf3U3zIoKO1BbHh6aUhJZQweOwSt4c2JrPDg9FP3Ltv3+YfEv7jIDB8275tVnO/qOHbfuYg3kzw6Je7uWw==",
"dev": true,
"requires": {
"eslint-restricted-globals": "^0.1.1",
"object.assign": "^4.1.0",
"object.entries": "^1.0.4"
}
},
"eslint-config-standard": {
"version": "12.0.0",
"resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-12.0.0.tgz",
@@ -953,6 +1000,12 @@
"integrity": "sha512-OwxJkR6TQiYMmt1EsNRMe5qG3GsbjlcOhbGUBY4LtavF9DsLaTcoR+j2Tdjqi23oUwKNUqX7qcn5fPStafMdlA==",
"dev": true
},
"eslint-restricted-globals": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz",
"integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=",
"dev": true
},
"eslint-scope": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz",
@@ -1023,13 +1076,13 @@
"dev": true
},
"external-editor": {
"version": "2.2.0",
"resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
"integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz",
"integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==",
"dev": true,
"requires": {
"chardet": "^0.4.0",
"iconv-lite": "^0.4.17",
"chardet": "^0.7.0",
"iconv-lite": "^0.4.24",
"tmp": "^0.0.33"
}
},
@@ -1219,6 +1272,14 @@
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true
}
}
},
"has-flag": {
@@ -1316,21 +1377,21 @@
"dev": true
},
"inquirer": {
"version": "5.2.0",
"resolved": "http://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz",
"integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==",
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz",
"integrity": "sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==",
"dev": true,
"requires": {
"ansi-escapes": "^3.0.0",
"chalk": "^2.0.0",
"cli-cursor": "^2.1.0",
"cli-width": "^2.0.0",
"external-editor": "^2.1.0",
"external-editor": "^3.0.0",
"figures": "^2.0.0",
"lodash": "^4.3.0",
"lodash": "^4.17.10",
"mute-stream": "0.0.7",
"run-async": "^2.2.0",
"rxjs": "^5.5.2",
"rxjs": "^6.1.0",
"string-width": "^2.1.0",
"strip-ansi": "^4.0.0",
"through": "^2.3.6"
@@ -1788,6 +1849,30 @@
"integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==",
"dev": true
},
"object.assign": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
"integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"function-bind": "^1.1.1",
"has-symbols": "^1.0.0",
"object-keys": "^1.0.11"
}
},
"object.entries": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.0.4.tgz",
"integrity": "sha1-G/mk3SKI9bM/Opk9JXZh8F0WGl8=",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"es-abstract": "^1.6.1",
"function-bind": "^1.1.0",
"has": "^1.0.1"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -2187,6 +2272,16 @@
"warning": "^4.0.1"
}
},
"react-sortable-hoc": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-sortable-hoc/-/react-sortable-hoc-0.8.3.tgz",
"integrity": "sha512-vt2qQ9DnPLjGZ9osM2jBULdi7WfFXtYVuHvjHX8o2em7Rcla9FXIG60aWFbvvpFC1iXyATw5PWZX0B57EUOYfQ==",
"requires": {
"babel-runtime": "^6.11.6",
"invariant": "^2.2.1",
"prop-types": "^15.5.7"
}
},
"react-text-mask": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/react-text-mask/-/react-text-mask-5.4.1.tgz",
@@ -2327,20 +2422,12 @@
"dev": true
},
"rxjs": {
"version": "5.5.12",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz",
"integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==",
"version": "6.3.3",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
"integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==",
"dev": true,
"requires": {
"symbol-observable": "1.0.1"
},
"dependencies": {
"symbol-observable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz",
"integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=",
"dev": true
}
"tslib": "^1.9.0"
}
},
"safer-buffer": {
@@ -2463,6 +2550,131 @@
"eslint-plugin-react": "~7.11.1",
"eslint-plugin-standard": "~4.0.0",
"standard-engine": "~9.0.0"
},
"dependencies": {
"chardet": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
"dev": true
},
"eslint": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-5.4.0.tgz",
"integrity": "sha512-UIpL91XGex3qtL6qwyCQJar2j3osKxK9e3ano3OcGEIRM4oWIpCkDg9x95AXEC2wMs7PnxzOkPZ2gq+tsMS9yg==",
"dev": true,
"requires": {
"ajv": "^6.5.0",
"babel-code-frame": "^6.26.0",
"chalk": "^2.1.0",
"cross-spawn": "^6.0.5",
"debug": "^3.1.0",
"doctrine": "^2.1.0",
"eslint-scope": "^4.0.0",
"eslint-utils": "^1.3.1",
"eslint-visitor-keys": "^1.0.0",
"espree": "^4.0.0",
"esquery": "^1.0.1",
"esutils": "^2.0.2",
"file-entry-cache": "^2.0.0",
"functional-red-black-tree": "^1.0.1",
"glob": "^7.1.2",
"globals": "^11.7.0",
"ignore": "^4.0.2",
"imurmurhash": "^0.1.4",
"inquirer": "^5.2.0",
"is-resolvable": "^1.1.0",
"js-yaml": "^3.11.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.3.0",
"lodash": "^4.17.5",
"minimatch": "^3.0.4",
"mkdirp": "^0.5.1",
"natural-compare": "^1.4.0",
"optionator": "^0.8.2",
"path-is-inside": "^1.0.2",
"pluralize": "^7.0.0",
"progress": "^2.0.0",
"regexpp": "^2.0.0",
"require-uncached": "^1.0.3",
"semver": "^5.5.0",
"strip-ansi": "^4.0.0",
"strip-json-comments": "^2.0.1",
"table": "^4.0.3",
"text-table": "^0.2.0"
}
},
"eslint-scope": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz",
"integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==",
"dev": true,
"requires": {
"esrecurse": "^4.1.0",
"estraverse": "^4.1.1"
}
},
"external-editor": {
"version": "2.2.0",
"resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
"integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
"dev": true,
"requires": {
"chardet": "^0.4.0",
"iconv-lite": "^0.4.17",
"tmp": "^0.0.33"
}
},
"inquirer": {
"version": "5.2.0",
"resolved": "http://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz",
"integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==",
"dev": true,
"requires": {
"ansi-escapes": "^3.0.0",
"chalk": "^2.0.0",
"cli-cursor": "^2.1.0",
"cli-width": "^2.0.0",
"external-editor": "^2.1.0",
"figures": "^2.0.0",
"lodash": "^4.3.0",
"mute-stream": "0.0.7",
"run-async": "^2.2.0",
"rxjs": "^5.5.2",
"string-width": "^2.1.0",
"strip-ansi": "^4.0.0",
"through": "^2.3.6"
}
},
"rxjs": {
"version": "5.5.12",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz",
"integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==",
"dev": true,
"requires": {
"symbol-observable": "1.0.1"
}
},
"symbol-observable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz",
"integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=",
"dev": true
},
"table": {
"version": "4.0.3",
"resolved": "http://registry.npmjs.org/table/-/table-4.0.3.tgz",
"integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==",
"dev": true,
"requires": {
"ajv": "^6.0.1",
"ajv-keywords": "^3.0.0",
"chalk": "^2.1.0",
"lodash": "^4.17.4",
"slice-ansi": "1.0.0",
"string-width": "^2.1.1"
}
}
}
},
"standard-engine": {
@@ -2502,14 +2714,6 @@
"dev": true,
"requires": {
"ansi-regex": "^3.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
"dev": true
}
}
},
"strip-bom": {
@@ -2539,15 +2743,13 @@
"integrity": "sha1-Kb9hXUqnEhvdiYsi1LP5vE4qoD0="
},
"table": {
"version": "4.0.3",
"resolved": "http://registry.npmjs.org/table/-/table-4.0.3.tgz",
"integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==",
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/table/-/table-5.1.0.tgz",
"integrity": "sha512-e542in22ZLhD/fOIuXs/8yDZ9W61ltF8daM88rkRNtgTIct+vI2fTnAyu/Db2TCfEcI8i7mjZz6meLq0nW7TYg==",
"dev": true,
"requires": {
"ajv": "^6.0.1",
"ajv-keywords": "^3.0.0",
"chalk": "^2.1.0",
"lodash": "^4.17.4",
"ajv": "^6.5.3",
"lodash": "^4.17.10",
"slice-ansi": "1.0.0",
"string-width": "^2.1.1"
}
+6 -1
View File
@@ -13,6 +13,10 @@
},
"devDependencies": {
"babel-eslint": "^10.0.1",
"eslint": "^5.8.0",
"eslint-config-airbnb-base": "^13.1.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-react": "^7.11.1",
"react-hot-loader": "^4.3.11",
"standard": "^12.0.1"
},
@@ -28,6 +32,7 @@
"react": "^16.5.2",
"react-apollo": "^2.2.4",
"react-dom": "^16.6.0",
"react-router-dom": "^4.3.1"
"react-router-dom": "^4.3.1",
"react-sortable-hoc": "^0.8.3"
}
}
@@ -0,0 +1,109 @@
import React from 'react';
import {
TextField,
Button,
FormGroup,
Typography,
Grid,
} from '@material-ui/core';
import {
ChevronLeft,
ChevronRight,
} from '@material-ui/icons';
import { DateTimePicker } from 'material-ui-pickers';
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
class Basic extends React.Component {
render() {
const { classes, event, edit } = this.props;
return (
<React.Fragment>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
These are the basic information you need to input in order to create an event.
There might be some heavy changes in the near future as the application is still at a very early stage.
</Typography>
<TextField
label='Public id'
value='Your public ID will be generated automatically'
className={classes.inputField}
disabled
/>
<TextField
label='Name'
value={event.name}
className={classes.inputField}
onChange={newVal => edit('name', newVal.target.value)}
/>
<TextField
multiline
label='Description'
value={event.description}
className={classes.inputField}
onChange={newVal => edit('description', newVal.target.value)}
/>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
The dates are purely indicative, as it is important for you to make sure everything is
ready before manually triggering the beginning and end of the event.
If you are confident use the scheduler to start it for you(incoming).
</Typography>
<FormGroup row className={classes.inputField}>
<Grid container justify='space-around' >
<Grid item>
<DateTimePicker
autoOk
disablePast
format="DD' at 'HH:mm"
ampm={false}
showTabs={false}
leftArrowIcon={<ChevronLeft />}
rightArrowIcon={<ChevronRight />}
value={event.startDatetime}
helperText='Competition start date'
onChange={newVal => edit('startDatetime', newVal)}
/>
</Grid>
<Grid item>
<DateTimePicker
autoOk
disablePast
format="DD' at 'HH:mm"
ampm={false}
showTabs={false}
leftArrowIcon={<ChevronLeft />}
rightArrowIcon={<ChevronRight />}
value={event.finishDatetime}
helperText='Competition finishing date'
onChange={newVal => edit('finishDatetime', newVal)}
/>
</Grid>
</Grid>
</FormGroup>
<Grid container justify='center' >
<Grid item>
<Button
className={classes.bottomButton}
variant='contained'
color='secondary'
onClick={() => edit('value', 1)}
>
Go to technical tab
</Button>
<Button className={classes.bottomButton} type='submit' variant='contained' color='secondary'>
Or Create event
</Button>
</Grid>
</Grid>
</React.Fragment>
);
}
}
export default withStyles(styles)(Basic);
@@ -0,0 +1,27 @@
import React from 'react';
import { Typography } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
class PresentationPage extends React.Component {
render() {
const { classes } = this.props;
return (
<React.Fragment>
<Typography
className={classes.title}
variant='h4'
align='center'
color='textPrimary'
gutterBottom
>
PresentationPage
</Typography>
</React.Fragment>
);
}
}
export default withStyles(styles)(PresentationPage);
@@ -0,0 +1,27 @@
import React from 'react';
import { Typography } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
class TeamsServer extends React.Component {
render() {
const { classes } = this.props;
return (
<React.Fragment>
<Typography
className={classes.title}
variant='h4'
align='center'
color='textPrimary'
gutterBottom
>
TeamsServer
</Typography>
</React.Fragment>
);
}
}
export default withStyles(styles)(TeamsServer);
@@ -0,0 +1,80 @@
import React from 'react';
import {
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
Button,
TextField,
} from '@material-ui/core';
import { Mutation } from 'react-apollo';
import { getOptionsCalls } from '../../../../../GraphQL/Calls/index';
class NewFormula extends React.Component {
constructor() {
super();
this.state = { name: '' };
}
render() {
const { name } = this.state;
return (
<Dialog
open={true}
onClose={() => this.props.closeDialogs()}
aria-labelledby='createFormula-dialog-title'
>
<DialogTitle id='createFormula-dialog-title'>
Create a new formula
</DialogTitle>
<DialogContent>
<DialogContentText>
At least for now, all the formulas are publically available, creating it here will let you select it in the select element.
</DialogContentText>
<Mutation mutation={getOptionsCalls.EVENTS_CREATEFORMULA}
update={(store, { data }) => {
const { events_Formulas: formulas } = store.readQuery({
query: getOptionsCalls.EVENTS_FORMULAS,
});
store.writeQuery({
query: getOptionsCalls.EVENTS_FORMULAS,
data: { events_Formulas: formulas.concat([data.events_CreateFormula]) },
});
this.props.closeDialogs();
}
}
>
{createFormula => (
<div className='container'>
<form
onSubmit={(e) => {
e.preventDefault();
createFormula({
variables: {
formula: { name },
},
});
}}
>
<TextField
label='Name'
value={name}
onChange={e => this.setState({ name: e.target.value })}
fullWidth
/>
<Button type='submit' variant='contained' color='secondary'>Create a new formula</Button>
</form>
</div>
)}
</Mutation>
</DialogContent>
</Dialog>
);
}
}
export default NewFormula;
@@ -0,0 +1,110 @@
import React from 'react';
import {
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
Button,
TextField,
} from '@material-ui/core';
import { Mutation } from 'react-apollo';
import { getOptionsCalls } from '../../../../../GraphQL/Calls/index';
class NewPlotter extends React.Component {
constructor() {
super();
this.state = {
name: '',
host: '',
repo: '',
moduleName: '',
};
}
render() {
const {
name, host, repo, moduleName,
} = this.state;
return (
<Dialog
open={true}
onClose={() => this.props.closeDialogs()}
aria-labelledby='createPlotter-dialog-title'
>
<DialogTitle id='createPlotter-dialog-title'>
Create a new plotter
</DialogTitle>
<DialogContent>
<DialogContentText>
At least for now, all the plotters are publically available, creating it here will let you select it in the select element.
</DialogContentText>
<Mutation mutation={getOptionsCalls.EVENTS_CREATEPLOTTER}
update={(store, { data }) => {
const { events_Plotters: plotters } = store.readQuery({
query: getOptionsCalls.EVENTS_PLOTTERS,
});
store.writeQuery({
query: getOptionsCalls.EVENTS_PLOTTERS,
data: { events_Plotters: plotters.concat([data.events_CreatePlotter]) },
});
this.props.closeDialogs();
}
}
>
{createPlotter => (
<div className='container'>
<form
onSubmit={(e) => {
e.preventDefault();
createPlotter({
variables: {
plotter: {
name,
host,
repo,
moduleName,
},
},
});
}}
>
<TextField
label='Name'
value={name}
onChange={e => this.setState({ name: e.target.value })}
fullWidth
/>
<TextField
label='Host'
value={host}
onChange={e => this.setState({ host: e.target.value })}
fullWidth
/>
<TextField
label='Repository'
value={repo}
onChange={e => this.setState({ repo: e.target.value })}
fullWidth
/>
<TextField
label='Module Name'
value={moduleName}
onChange={e => this.setState({ moduleName: e.target.value })}
fullWidth
/>
<Button type='submit' variant='contained' color='secondary'>Create a new plotter</Button>
</form>
</div>
)}
</Mutation>
</DialogContent>
</Dialog>
);
}
}
export default NewPlotter;
@@ -0,0 +1,142 @@
import React from 'react';
import { Query } from 'react-apollo';
import {
Typography,
FormControl,
InputLabel,
Input,
Select,
FormHelperText,
MenuItem,
Grid,
Button,
} from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from '../../styles';
import { getOptionsCalls } from '../../../../../GraphQL/Calls/index';
import NewPlotter from './NewPlotter';
import NewFormula from './NewFormula';
class Technical extends React.Component {
constructor(props) {
super(props);
this.state = {
isNewFormulaOpen: false,
isNewPlotterOpen: false,
};
}
closeDialogs = () => {
this.setState({ isNewFormulaOpen: false, isNewPlotterOpen: false });
}
render() {
const { classes, event, edit } = this.props;
const { isNewPlotterOpen, isNewFormulaOpen } = this.state;
return (
<React.Fragment>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
Select the formula and the plotter you want to use, you can also create your own with the corresponding button.
</Typography>
<FormControl className={classes.inputField}>
<InputLabel shrink htmlFor='select'>
Select the formula
</InputLabel>
<Query query={getOptionsCalls.EVENTS_FORMULAS} >
{({ loading, error, data }) => {
if (loading) {
return (
<Select
value='loading'
input={<Input />}
displayEmpty
className={classes.selectEmpty}
disabled
>
<MenuItem key='1' value='loading'>Loading possibilities...</MenuItem>
</Select>
);
}
if (error) return `Error! ${error.message}`;
const selects = data.events_Formulas.map((formula, index) => (
<MenuItem key={index} value={formula.id}>{formula.name}</MenuItem>
));
return (
<React.Fragment>
<Select
value={event.formulaId}
input={<Input />}
displayEmpty
className={classes.selectEmpty}
onChange={newVal => edit('formulaId', newVal.target.value)}
>
{selects}
</Select>
{ isNewFormulaOpen ? <NewFormula closeDialogs={() => this.closeDialogs()} /> : ''}
</React.Fragment>
);
}}
</Query>
<FormHelperText className={classes.clickable} onClick={() => { this.setState({ isNewFormulaOpen: true }); }}>
To create a new formula, click here
</FormHelperText>
</FormControl>
<FormControl className={classes.inputField}>
<InputLabel shrink htmlFor='select'>
Select the Plotter
</InputLabel>
<Query query={getOptionsCalls.EVENTS_PLOTTERS} >
{({ loading, error, data }) => {
if (loading) {
return (
<Select
value='loading'
input={<Input />}
displayEmpty
className={classes.selectEmpty}
disabled
>
<MenuItem key='1' value='loading'>Loading possibilities...</MenuItem>
</Select>
);
}
if (error) return `Error! ${error.message}`;
const selects = data.events_Plotters.map((plotter, index) => (
<MenuItem key={index} value={plotter.id}>{plotter.name}</MenuItem>
));
return (
<React.Fragment>
<Select
value={event.plotterId}
input={<Input />}
displayEmpty
className={classes.selectEmpty}
onChange={newVal => edit('plotterId', newVal.target.value)}
>
{selects}
</Select>
{ isNewPlotterOpen ? <NewPlotter closeDialogs={() => this.closeDialogs()} /> : ''}
</React.Fragment>
);
}}
</Query>
<FormHelperText className={classes.clickable} onClick={() => { this.setState({ isNewPlotterOpen: true }); }} >
To create a new plotter, click here
</FormHelperText>
</FormControl>
<Grid container justify='center' >
<Grid item>
<Button className={classes.bottomButton} type='submit' variant='contained' color='secondary'>
Create the event
</Button>
</Grid>
</Grid>
</React.Fragment>
);
}
}
export default withStyles(styles)(Technical);
@@ -0,0 +1,11 @@
import Basic from './Basic';
import PresentationPage from './PresentationPage';
import TeamsServer from './TeamsServer';
import Technical from './Technical';
export {
Basic,
PresentationPage,
TeamsServer,
Technical,
};
+165
View File
@@ -0,0 +1,165 @@
import React from 'react';
import { Mutation } from 'react-apollo';
import { DateTime } from 'luxon';
import {
Paper,
Typography,
AppBar,
Tabs,
Tab,
} from '@material-ui/core';
import {
Face as BasicIcon,
Alarm as TechnicalIcon,
Group as TeamAndServerIcon,
PresentToAll as PresentationIcon,
} from '@material-ui/icons';
import { withStyles } from '@material-ui/core/styles';
import styles from './styles';
import {
Basic,
PresentationPage,
TeamsServer,
Technical,
} from './Tabs';
import { hostedEventsCalls } from '../../../GraphQL/Calls';
function TabContainer(props) {
return (
<Typography component='div' style={{ padding: 8 * 3 }}>
{props.children}
</Typography>
);
}
class Create extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 0,
name: '',
description: '',
startDatetime: DateTime.local().plus({ days: 1 }).startOf('day'),
finishDatetime: DateTime.local().plus({ days: 8 }).startOf('day'),
formulaId: '',
plotterId: '',
};
}
handleTabChange = (event, value) => {
this.setState({ value });
}
handleEventChange = (newType, newVal) => {
this.setState({ [newType]: newVal });
}
render() {
const {
name,
description,
startDatetime,
finishDatetime,
value,
formulaId,
plotterId,
} = this.state;
const { classes } = this.props;
return (
<Mutation mutation={hostedEventsCalls.EVENTS_CREATEEVENT}
update={(store, { data }) => {
this.props.history.push(`/events/edit/${data.events_CreateEvent.id}`);
}
}
>
{hostEvent => (
<div className={classes.root}>
<AppBar position='static' color='default'>
<Tabs
value={value}
onChange={this.handleTabChange}
scrollable
scrollButtons='off'
indicatorColor='primary'
textColor='primary'
>
<Tab
className={classes.tabTitle}
label='Basic information'
icon={<BasicIcon />}
/>
<Tab
className={classes.tabTitle}
label='Technical information'
icon={<TechnicalIcon />}
/>
<Tab
className={classes.tabTitle}
label='Teams &amp; server setup(disabled)'
icon={<TeamAndServerIcon />}
disabled
/>
<Tab
className={classes.tabTitle}
label='Presentation page(disabled)'
icon={<PresentationIcon />}
disabled
/>
</Tabs>
</AppBar>
<Paper className={classes.paperRoot}>
<Typography className={classes.typography} variant='headline' gutterBottom>
Create a new event
</Typography>
<form
onSubmit={(e) => {
e.preventDefault();
hostEvent({
variables: {
event: {
name,
description,
startDatetime: startDatetime.valueOf() / 1000,
finishDatetime: finishDatetime.valueOf() / 1000,
formulaId,
plotterId,
},
},
});
}}
>
{value === 0 && <TabContainer>
<Basic
event={{
name,
description,
startDatetime,
finishDatetime,
}}
edit={(newType, newVal) => this.handleEventChange(newType, newVal)}
/>
</TabContainer>}
{value === 1 && <TabContainer>
<Technical
event={{
formulaId,
plotterId,
}}
edit={(newType, newVal) => this.handleEventChange(newType, newVal)}
/>
</TabContainer>}
{value === 2 && <TabContainer><TeamsServer /></TabContainer>}
{value === 3 && <TabContainer><PresentationPage /></TabContainer>}
</form>
</Paper>
</div>
)}
</Mutation>
);
}
}
export default withStyles(styles)(Create);
@@ -0,0 +1,60 @@
const styles = theme => ({
root: {
flexGrow: 1,
width: '100%',
backgroundColor: theme.palette.background.paper,
padding: 0,
margin: 0,
},
tabTitle: {
width: '25%',
maxWidth: 'none',
},
clickable: {
cursor: 'pointer',
},
card: {
flexGrow: 1,
padding: 20,
marginTop: 20,
marginBottom: 20,
marginLeft: 400,
marginRight: 400,
},
buttonList: {
margin: theme.spacing.unit,
float: 'right',
},
buttonGrid: {
marginTop: -20,
},
title: {
marginTop: 20,
},
paperRoot: {
width: '50%',
flexGrow: 1,
padding: 10,
marginLeft: '25%',
marginTop: '2%',
},
inputField: {
width: '80%',
marginLeft: '10%',
marginTop: 25,
},
typography: {
width: '80%',
marginLeft: '10%',
marginTop: 40,
},
selectEmpty: {
marginTop: theme.spacing.unit * 2,
},
bottomButton: {
padding: 15,
margin: 20,
},
});
export default styles;
+13 -13
View File
@@ -1,15 +1,15 @@
import React from 'react'
import { Query } from 'react-apollo'
import React from 'react';
import { Query } from 'react-apollo';
import Typography from '@material-ui/core/Typography'
import { withStyles } from '@material-ui/core/styles'
import Typography from '@material-ui/core/Typography';
import { withStyles } from '@material-ui/core/styles';
import styles from './styles'
import styles from './styles';
import { showEventCalls } from '../../../GraphQL/Calls/index'
import { showEventCalls } from '../../../GraphQL/Calls/index';
class Edit extends React.Component {
render () {
render() {
return (
<React.Fragment>
<Typography
@@ -22,21 +22,21 @@ class Edit extends React.Component {
</Typography>
<Query
query={showEventCalls.EVENTS_EVENT}
variables={{ designator: this.props.match.params.slug }}
variables={{ eventId: this.props.match.params.slug }}
>
{({ loading, error, data }) => {
if (loading) return 'Loading...'
if (error) return `Error! ${error.message}`
if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;
return (
<p>
{data.events_Event.description}
</p>
)
);
}}
</Query>
</React.Fragment>
)
);
}
}
export default withStyles(styles)(Edit)
export default withStyles(styles)(Edit);
+3 -3
View File
@@ -1,4 +1,4 @@
const styles = theme => ({
})
const styles = () => ({
});
export default styles
export default styles;
+13 -13
View File
@@ -1,15 +1,15 @@
import React from 'react'
import { Query } from 'react-apollo'
import React from 'react';
import { Query } from 'react-apollo';
import Typography from '@material-ui/core/Typography'
import { withStyles } from '@material-ui/core/styles'
import Typography from '@material-ui/core/Typography';
import { withStyles } from '@material-ui/core/styles';
import styles from './styles'
import styles from './styles';
import { showEventCalls } from '../../../GraphQL/Calls/index'
import { showEventCalls } from '../../../GraphQL/Calls/index';
class Show extends React.Component {
render () {
render() {
return (
<React.Fragment>
<Typography
@@ -22,21 +22,21 @@ class Show extends React.Component {
</Typography>
<Query
query={showEventCalls.EVENTS_EVENT}
variables={{ designator: this.props.match.params.slug }}
variables={{ eventId: this.props.match.params.slug }}
>
{({ loading, error, data }) => {
if (loading) return 'Loading...'
if (error) return `Error! ${error.message}`
if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;
return (
<p>
{data.events_Event.description}
</p>
)
);
}}
</Query>
</React.Fragment>
)
);
}
}
export default withStyles(styles)(Show)
export default withStyles(styles)(Show);
+3 -3
View File
@@ -1,4 +1,4 @@
const styles = theme => ({
})
const styles = () => ({
});
export default styles
export default styles;
+3 -7
View File
@@ -1,9 +1,5 @@
import React from 'react'
import React from 'react';
class Index extends React.Component {
render () {
return <p>Here will come a list the competitions you applied for</p>
}
}
const Index = () => <p>Here will come a list the competitions you applied for</p>;
export default Index
export default Index;
+19 -17
View File
@@ -1,27 +1,27 @@
import React from 'react'
import { Link } from 'react-router-dom'
import React from 'react';
import { Link } from 'react-router-dom';
import {
Grid, Paper,
Typography,
Button
} from '@material-ui/core'
import { withStyles } from '@material-ui/core/styles'
import styles from './styles'
Button,
} from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from './styles';
import { toLocalTime } from '../../utils'
import { toLocalTime } from '../../utils';
class Event extends React.Component {
render () {
const classes = this.props.classes
render() {
const { classes } = this.props;
const {
id,
name,
designator,
startDatetime,
finishDatetime,
host,
description
} = this.props.event
description,
} = this.props.event;
return (
<Paper className={classes.card}>
<Grid container spacing={16}>
@@ -31,7 +31,9 @@ class Event extends React.Component {
<Typography gutterBottom>To : {toLocalTime(finishDatetime)} </Typography>
</Grid>
<Grid item xs>
<Typography gutterBottom>Hosted by: {host.alias} ({host.lastName} {host.firstName}) </Typography>
<Typography gutterBottom>
Hosted by: {host.alias} ({host.lastName} {host.firstName})
</Typography>
<Typography gutterBottom>Formula: </Typography>
<Typography gutterBottom>First prize: </Typography>
</Grid>
@@ -48,7 +50,7 @@ class Event extends React.Component {
color='primary'
size='small'
component={Link}
to={`/edit/${designator}`}
to={`/events/edit/${id}`}
>
Edit
</Button>
@@ -58,7 +60,7 @@ class Event extends React.Component {
color='primary'
size='small'
component={Link}
to={'/show/' + designator}
to={`/events/show/${id}`}
>
Show
</Button>
@@ -67,8 +69,8 @@ class Event extends React.Component {
</Grid>
</Grid>
</Paper>
)
);
}
}
export default withStyles(styles)(Event)
export default withStyles(styles)(Event);
-98
View File
@@ -1,98 +0,0 @@
import React from 'react'
import { Mutation } from 'react-apollo'
import { hostedEventsCalls } from '../../GraphQL/Calls/index'
import { DateTime } from 'luxon'
import {
Button,
TextField
} from '@material-ui/core'
import { ChevronLeft, ChevronRight } from '@material-ui/icons'
import { DateTimePicker } from 'material-ui-pickers'
class New extends React.Component {
constructor (props) {
super(props)
this.state = {
name: '',
description: '',
startDatetime: DateTime.local().plus({ days: 1 }).startOf('day'),
finishDatetime: DateTime.local().plus({ days: 8 }).startOf('day')
}
}
render () {
const { name, description, startDatetime, finishDatetime } = this.state
return (
<Mutation mutation={hostedEventsCalls.EVENTS_HOSTEVENT}
update={(store, { data }) => {
const { events_EventsByHost: hostedEvents } = store.readQuery({ query: hostedEventsCalls.EVENTS_EVENTSBYHOST })
store.writeQuery({
query: hostedEventsCalls.EVENTS_EVENTSBYHOST,
data: { events_EventsByHost: hostedEvents.concat([data.events_HostEvent]) }
})
this.props.handleNewEvent(data.events_HostEvent)
}
}
>
{(hostEvent, { data }) => (
<div className='container'>
<form
onSubmit={e => {
e.preventDefault()
hostEvent({ variables: {
name: name,
description: description,
startDatetime: startDatetime.valueOf() / 1000,
finishDatetime: startDatetime.valueOf() / 1000
} })
}}
>
<TextField
label='Name'
value={name}
onChange={(e) => this.setState({ name: e.target.value })}
fullWidth
/>
<TextField
multiline
label='Description'
value={description}
onChange={(e) => this.setState({ description: e.target.value })}
fullWidth
/>
<DateTimePicker
autoOk
disablePast
format="DD' at 'HH:mm"
ampm={false}
showTabs={false}
leftArrowIcon={<ChevronLeft />}
rightArrowIcon={<ChevronRight />}
value={startDatetime}
onChange={(date) => this.setState({ startDatetime: date })}
helperText='Competition start date'
/>
<DateTimePicker
autoOk
disablePast
format="DD' at 'HH:mm"
ampm={false}
showTabs={false}
leftArrowIcon={<ChevronLeft />}
rightArrowIcon={<ChevronRight />}
value={finishDatetime}
onChange={(date) => this.setState({ finishDatetime: date })}
helperText='Competition finishing date'
/>
<Button type='submit' variant='contained' color='secondary'>Create New Project</Button>
</form>
<div className='form-close' onClick={() => this.clearTempStates()} />
</div>
)}
</Mutation>
)
}
}
export default New
+25 -76
View File
@@ -1,81 +1,30 @@
import React from 'react'
import { Query } from 'react-apollo'
import React from 'react';
import { Query } from 'react-apollo';
import {
Button,
Dialog,
DialogContent,
DialogContentText,
DialogTitle
} from '@material-ui/core'
import { hostedEventsCalls } from '../../GraphQL/Calls/index';
import { withStyles } from '@material-ui/core/styles'
import styles from './styles'
import Event from './Event';
import { hostedEventsCalls } from '../../GraphQL/Calls/index'
const HostedEvent = () => (
<React.Fragment>
<Query
query={hostedEventsCalls.EVENTS_EVENTSBYHOST}
>
{({ loading, error, data }) => {
if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;
const list = data.events_EventsByHost.map((event, index) => (
<Event key={index} event={event} />
));
return (
<React.Fragment>
{ list }
</React.Fragment>
);
}}
</Query>
</React.Fragment>
);
import New from './New'
import Event from './Event'
class HostedEvent extends React.Component {
constructor (props) {
super(props)
this.state = {
isNewEventOpen: false
}
}
handleNewEvent = (event) => {
this.props.history.push(`/edit/${event.designator}`)
};
render () {
const { classes } = this.props
return (
<React.Fragment>
<Button variant='contained' color='secondary'
aria-label='addNewEvent' className={classes.addButton}
onClick={() => { this.setState({ isNewEventOpen: true }) }} >
Host a new event
</Button>
<Query
query={hostedEventsCalls.EVENTS_EVENTSBYHOST}
>
{({ loading, error, data }) => {
if (loading) return 'Loading...'
if (error) return `Error! ${error.message}`
const list = data.events_EventsByHost.map((event, index) => {
return (
<Event key={index} event={event} />
)
})
return (
<React.Fragment>
{ list }
</React.Fragment>
)
}}
</Query>
<Dialog
open={this.state.isNewEventOpen}
onClose={() => { this.setState({ isNewEventOpen: false }) }}
aria-labelledby='addEvent-dialog-title'
>
<DialogTitle id='addEvent-dialog-title'>
Host an event
</DialogTitle>
<DialogContent>
<DialogContentText>
Here you will add just the minimal information, will be settable in the edit page of your event.
</DialogContentText>
<New handleNewEvent={this.handleNewEvent} classes={classes} />
</DialogContent>
</Dialog>
</React.Fragment>
)
}
}
export default withStyles(styles)(HostedEvent)
export default HostedEvent;
+5 -12
View File
@@ -5,22 +5,15 @@ const styles = theme => ({
marginTop: 20,
marginBottom: 20,
marginLeft: 400,
marginRight: 400
marginRight: 400,
},
buttonList: {
margin: theme.spacing.unit,
float: 'right'
float: 'right',
},
buttonGrid: {
marginTop: -20
marginTop: -20,
},
addButton: {
display: 'block',
padding: 20,
marginTop: 20,
marginRight: 20,
marginLeft: 'auto'
}
})
});
export default styles
export default styles;
+18 -16
View File
@@ -1,27 +1,27 @@
import React from 'react'
import { Link } from 'react-router-dom'
import React from 'react';
import { Link } from 'react-router-dom';
import {
Grid, Paper,
Typography,
Button
} from '@material-ui/core'
import { withStyles } from '@material-ui/core/styles'
import styles from './styles'
Button,
} from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import styles from './styles';
import { toLocalTime } from '../../utils'
import { toLocalTime } from '../../utils';
class Event extends React.Component {
render () {
const classes = this.props.classes
render() {
const { classes } = this.props;
const {
id,
name,
designator,
startDatetime,
finishDatetime,
host,
description
} = this.props.event
description,
} = this.props.event;
return (
<Paper className={classes.card}>
<Grid container spacing={16}>
@@ -31,7 +31,9 @@ class Event extends React.Component {
<Typography gutterBottom>To : {toLocalTime(finishDatetime)} </Typography>
</Grid>
<Grid item xs>
<Typography gutterBottom>Hosted by: {host.alias} ({host.lastName} {host.firstName}) </Typography>
<Typography gutterBottom>
Hosted by: {host.alias} ({host.lastName} {host.firstName})
</Typography>
<Typography gutterBottom>Formula: </Typography>
<Typography gutterBottom>First prize: </Typography>
</Grid>
@@ -48,7 +50,7 @@ class Event extends React.Component {
color='primary'
size='small'
component={Link}
to={'/show/' + designator}
to={`/events/show/${id}`}
>
Show
</Button>
@@ -57,8 +59,8 @@ class Event extends React.Component {
</Grid>
</Grid>
</Paper>
)
);
}
}
export default withStyles(styles)(Event)
export default withStyles(styles)(Event);
+13 -15
View File
@@ -1,21 +1,19 @@
import React from 'react'
import { Typography } from '@material-ui/core'
import React from 'react';
import { Typography } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles'
import styles from '../styles'
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
import Event from '../Event'
import Event from '../Event';
class Future extends React.Component {
render () {
const classes = this.props.classes
const { FutureEvents } = this.props
render() {
const { classes } = this.props;
const { FutureEvents } = this.props;
const futureEvents = FutureEvents.map((event, index) => {
return (
<Event key={index} event={event} />
)
})
const futureEvents = FutureEvents.map((event, index) => (
<Event key={index} event={event} />
));
return (
<React.Fragment>
<Typography
@@ -29,8 +27,8 @@ class Future extends React.Component {
</Typography>
{futureEvents}
</React.Fragment>
)
);
}
}
export default withStyles(styles)(Future)
export default withStyles(styles)(Future);
+8 -8
View File
@@ -1,12 +1,12 @@
import React from 'react'
import { Typography } from '@material-ui/core'
import React from 'react';
import { Typography } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles'
import styles from '../styles'
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
class History extends React.Component {
render () {
const classes = this.props.classes
render() {
const { classes } = this.props;
return (
<Typography
className={classes.title}
@@ -17,8 +17,8 @@ class History extends React.Component {
>
Your old events (maybe here, maybe not, who knows)
</Typography>
)
);
}
}
export default withStyles(styles)(History)
export default withStyles(styles)(History);
+16 -20
View File
@@ -1,26 +1,22 @@
import React from 'react'
import { Typography } from '@material-ui/core'
import React from 'react';
import { Typography } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles'
import styles from '../styles'
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
import Event from '../Event'
import Event from '../Event';
class Incoming extends React.Component {
render () {
const classes = this.props.classes
const { IncomingEvents, OngoingEvents } = this.props
render() {
const { classes } = this.props;
const { IncomingEvents, OngoingEvents } = this.props;
const incomingEvents = IncomingEvents.map((event, index) => {
return (
<Event key={index} event={event} />
)
})
const ongoingEvents = OngoingEvents.map((event, index) => {
return (
<Event key={index} event={event} />
)
})
const incomingEvents = IncomingEvents.map((event, index) => (
<Event key={index} event={event} />
));
const ongoingEvents = OngoingEvents.map((event, index) => (
<Event key={index} event={event} />
));
return (
<React.Fragment>
<Typography
@@ -49,8 +45,8 @@ class Incoming extends React.Component {
</Typography>
{incomingEvents}
</React.Fragment>
)
);
}
}
export default withStyles(styles)(Incoming)
export default withStyles(styles)(Incoming);
+13 -15
View File
@@ -1,21 +1,19 @@
import React from 'react'
import { Typography } from '@material-ui/core'
import React from 'react';
import { Typography } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles'
import styles from '../styles'
import { withStyles } from '@material-ui/core/styles';
import styles from '../styles';
import Event from '../Event'
import Event from '../Event';
class Past extends React.Component {
render () {
const classes = this.props.classes
const { PastEvents } = this.props
render() {
const { classes } = this.props;
const { PastEvents } = this.props;
const pastEvents = PastEvents.map((event, index) => {
return (
<Event key={index} event={event} />
)
})
const pastEvents = PastEvents.map((event, index) => (
<Event key={index} event={event} />
));
return (
<React.Fragment>
<Typography
@@ -29,8 +27,8 @@ class Past extends React.Component {
</Typography>
{pastEvents}
</React.Fragment>
)
);
}
}
export default withStyles(styles)(Past)
export default withStyles(styles)(Past);
+6 -6
View File
@@ -1,11 +1,11 @@
import Future from './Future'
import History from './History'
import Incoming from './Incoming'
import Past from './Past'
import Future from './Future';
import History from './History';
import Incoming from './Incoming';
import Past from './Past';
export {
Future,
History,
Incoming,
Past
}
Past,
};
+38 -34
View File
@@ -1,68 +1,70 @@
import React from 'react'
import { Query } from 'react-apollo'
import { DateTime } from 'luxon'
import React from 'react';
import { Query } from 'react-apollo';
import { DateTime } from 'luxon';
import {
Typography,
AppBar,
Tabs,
Tab
} from '@material-ui/core'
Tab,
} from '@material-ui/core';
import {
GetApp as IncomingIcon,
AlarmAdd as FutureIcon,
History as HistoryIcon
} from '@material-ui/icons'
History as HistoryIcon,
} from '@material-ui/icons';
import { withStyles } from '@material-ui/core/styles'
import styles from './styles'
import { withStyles } from '@material-ui/core/styles';
import styles from './styles';
import { listEventsCalls } from '../../GraphQL/Calls/index'
import { listEventsCalls } from '../../GraphQL/Calls/index';
import {
Future,
History,
Incoming,
Past
} from './Tabs'
Past,
} from './Tabs';
function TabContainer (props) {
function TabContainer(props) {
return (
<Typography component='div' style={{ padding: 8 * 3 }}>
{props.children}
</Typography>
)
);
}
class Search extends React.Component {
constructor (props) {
super(props)
constructor(props) {
super(props);
this.state = {
value: 0
}
value: 0,
};
}
handleChange = (event, value) => {
this.setState({ value })
this.setState({ value });
}
render () {
const classes = this.props.classes
const { value } = this.state
render() {
const { classes } = this.props;
const { value } = this.state;
return (
<Query
query={listEventsCalls.EVENTS_EVENTS}
>
{({ loading, error, data }) => {
if (loading) return 'Loading...'
if (error) return `Error! ${error.message}`
const now = ~~(DateTime.local().valueOf() / 1000)
const inTwoWeeks = ~~(DateTime.local().plus({ weeks: 2 }).valueOf() / 1000)
if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;
const now = Math.floor(DateTime.local().valueOf() / 1000);
const inTwoWeeks = Math.floor(DateTime.local().plus({ weeks: 2 }).valueOf() / 1000);
const IncomingEvents = data.events_Events.filter(event => event.startDatetime > now && event.startDatetime < inTwoWeeks)
const OngoingEvents = data.events_Events.filter(event => event.finishDatetime > now && event.startDatetime < now)
const FutureEvents = data.events_Events.filter(event => event.startDatetime > now)
const PastEvents = data.events_Events.filter(event => event.finishDatetime < now)
const IncomingEvents = data.events_Events.filter(event => event.startDatetime > now
&& event.startDatetime < inTwoWeeks);
const OngoingEvents = data.events_Events.filter(event => event.finishDatetime > now
&& event.startDatetime < now);
const FutureEvents = data.events_Events.filter(event => event.startDatetime > now);
const PastEvents = data.events_Events.filter(event => event.finishDatetime < now);
return (
<React.Fragment>
@@ -98,17 +100,19 @@ class Search extends React.Component {
/>
</Tabs>
</AppBar>
{value === 0 && <TabContainer><Incoming IncomingEvents={IncomingEvents} OngoingEvents={OngoingEvents} /></TabContainer>}
{value === 0 && <TabContainer>
<Incoming IncomingEvents={IncomingEvents} OngoingEvents={OngoingEvents} />
</TabContainer>}
{value === 1 && <TabContainer><Future FutureEvents={FutureEvents} /></TabContainer>}
{value === 2 && <TabContainer><History /></TabContainer>}
{value === 3 && <TabContainer><Past PastEvents={PastEvents} /></TabContainer>}
</div>
</React.Fragment>
)
);
}}
</Query>
)
);
}
}
export default withStyles(styles)(Search)
export default withStyles(styles)(Search);
+9 -9
View File
@@ -4,11 +4,11 @@ const styles = theme => ({
width: '100%',
backgroundColor: theme.palette.background.paper,
padding: 0,
margin: 0
margin: 0,
},
tabTitle: {
width: '25%',
maxWidth: 'none'
maxWidth: 'none',
},
card: {
flexGrow: 1,
@@ -16,18 +16,18 @@ const styles = theme => ({
marginTop: 20,
marginBottom: 20,
marginLeft: 400,
marginRight: 400
marginRight: 400,
},
buttonList: {
margin: theme.spacing.unit,
float: 'right'
float: 'right',
},
buttonGrid: {
marginTop: -20
marginTop: -20,
},
title: {
marginTop: 20
}
})
marginTop: 20,
},
});
export default styles
export default styles;
+20 -8
View File
@@ -1,11 +1,23 @@
import GamesIcon from '@material-ui/icons/Games'
import SearchIcon from '@material-ui/icons/Search'
import LibraryAddIcon from '@material-ui/icons/LibraryAdd'
import {
Search,
GamepadRounded,
AccessibilityNew,
LibraryAdd,
} from '@material-ui/icons';
const data = [
{ title: 'Look for an event', to: '/', icon: SearchIcon, text: '' },
{ title: 'Events you are enrolled in', to: '/my', icon: GamesIcon, text: '' },
{ title: 'Host your own competition', to: '/host', icon: LibraryAddIcon, text: '' }
]
{
title: 'Look for an event', to: '/events/', icon: Search, text: '',
},
{
title: 'Events you are enrolled in', to: '/events/my', icon: GamepadRounded, text: '',
},
{
title: 'Your hosted competition', to: '/events/host', icon: AccessibilityNew, text: '',
},
{
title: 'Host a new competition', to: '/events/create', icon: LibraryAdd, text: '',
},
];
export default data
export default data;
+16 -15
View File
@@ -1,16 +1,18 @@
import React from 'react'
import { Link } from 'react-router-dom'
import classNames from 'classnames'
import React from 'react';
import { Link } from 'react-router-dom';
import classNames from 'classnames';
import { AppBar, Toolbar, Typography, Button } from '@material-ui/core'
import { withStyles } from '@material-ui/core/styles'
import {
AppBar, Toolbar, Typography, Button,
} from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import datas from './data'
import styles from './styles'
import datas from './data';
import styles from './styles';
const TopBar = ({ classes, user, match }) => {
const TopBar = ({ classes }) => {
const buttons = datas.map((data, index) => {
const Icon = data.icon
const Icon = data.icon;
return (
<Button
key={index}
@@ -22,9 +24,8 @@ const TopBar = ({ classes, user, match }) => {
to={data.to}>
<Icon className={classNames(classes.leftIcon, classes.iconSmall)} />
{data.text}
</Button>)
}
)
</Button>);
});
return (
<div className={classes.root}>
<AppBar position='static' color='secondary'>
@@ -36,7 +37,7 @@ const TopBar = ({ classes, user, match }) => {
</Toolbar>
</AppBar>
</div>
)
}
);
};
export default withStyles(styles)(TopBar)
export default withStyles(styles)(TopBar);
+9 -19
View File
@@ -1,37 +1,27 @@
const styles = theme => ({
root: {
flexGrow: 1
flexGrow: 1,
},
flex: {
flexGrow: 1,
marginLeft: 30
},
menuButton: {
marginLeft: -12,
marginRight: 20
marginLeft: 30,
},
cssRoot: {
color: '#FFFFFF',
backgroundColor: theme.palette.secondary,
'&:hover': {
backgroundColor: theme.palette.dark
backgroundColor: theme.palette.dark,
},
whiteSpace: 'nowrap',
paddingRight: 2 * theme.spacing.unit,
paddingLeft: 2 * theme.spacing.unit
},
button: {
margin: theme.spacing.unit
paddingLeft: 2 * theme.spacing.unit,
},
leftIcon: {
marginRight: theme.spacing.unit
},
rightIcon: {
marginLeft: theme.spacing.unit
marginRight: theme.spacing.unit,
},
iconSmall: {
fontSize: 20
}
})
fontSize: 20,
},
});
export default styles
export default styles;
+45
View File
@@ -0,0 +1,45 @@
import gql from 'graphql-tag';
import { formulaInfo, plotterInfo } from '../Fragments';
const EVENTS_FORMULAS = gql`
query Events_Formulas{
events_Formulas {
...FormulaInfo
}
}
${formulaInfo}
`;
const EVENTS_PLOTTERS = gql`
query Events_Plotters{
events_Plotters {
...PlotterInfo
}
}
${plotterInfo}
`;
const EVENTS_CREATEFORMULA = gql`
mutation Events_CreateFormula($formula: events_FormulaInput!) {
events_CreateFormula(formula: $formula) {
...FormulaInfo
}
}
${formulaInfo}
`;
const EVENTS_CREATEPLOTTER = gql`
mutation Events_CreatePlotter($plotter: events_PlotterInput!) {
events_CreatePlotter(plotter: $plotter) {
...PlotterInfo
}
}
${plotterInfo}
`;
export default {
EVENTS_PLOTTERS,
EVENTS_FORMULAS,
EVENTS_CREATEFORMULA,
EVENTS_CREATEPLOTTER,
};
+11 -11
View File
@@ -1,23 +1,23 @@
import gql from 'graphql-tag'
import { eventMinimalInfo } from '../Fragments'
import gql from 'graphql-tag';
import { eventMinimalInfo } from '../Fragments';
const EVENTS_HOSTEVENT = gql`
mutation Hosts_HostEvent($name: String!, $description: String!, $startDatetime: Int!, $finishDatetime: Int!) {
events_HostEvent(name: $name, description: $description, startDatetime: $startDatetime, finishDatetime: $finishDatetime) {
const EVENTS_CREATEEVENT = gql`
mutation Events_CreateEvent($event: events_EventInput!) {
events_CreateEvent(event: $event) {
...EventMinimalInfo
}
}
${eventMinimalInfo}
`
`;
const EVENTS_EVENTSBYHOST = gql`
query Hosts_EventsByHost{
query Events_EventsByHost{
events_EventsByHost {
...EventMinimalInfo
}
}
${eventMinimalInfo}
`
`;
export default {
EVENTS_HOSTEVENT,
EVENTS_EVENTSBYHOST
}
EVENTS_CREATEEVENT,
EVENTS_EVENTSBYHOST,
};
+7 -5
View File
@@ -1,9 +1,11 @@
import hostedEventsCalls from './hostedEvents'
import listEventsCalls from './listEvents'
import showEventCalls from './showEvent'
import hostedEventsCalls from './hostedEvents';
import listEventsCalls from './listEvents';
import showEventCalls from './showEvent';
import getOptionsCalls from './getOptions';
export {
hostedEventsCalls,
listEventsCalls,
showEventCalls
}
showEventCalls,
getOptionsCalls,
};
+6 -6
View File
@@ -1,14 +1,14 @@
import gql from 'graphql-tag'
import { eventMinimalInfo } from '../Fragments'
import gql from 'graphql-tag';
import { eventMinimalInfo } from '../Fragments';
const EVENTS_EVENTS = gql`
query Hosts_Events{
query Events_Events{
events_Events {
...EventMinimalInfo
}
}
${eventMinimalInfo}
`
`;
export default {
EVENTS_EVENTS
}
EVENTS_EVENTS,
};
+7 -7
View File
@@ -1,15 +1,15 @@
import gql from 'graphql-tag'
import { eventFullInfo } from '../Fragments'
import gql from 'graphql-tag';
import { eventFullInfo } from '../Fragments';
const EVENTS_EVENT = gql`
query Hosts_Event($designator: ID!) {
events_Event(designator: $designator) {
query Events_Event($eventId: ID!) {
events_Event(eventId: $eventId) {
...EventFullInfo
}
}
${eventFullInfo}
`
`;
export default {
EVENTS_EVENT
}
EVENTS_EVENT,
};
+7 -5
View File
@@ -1,9 +1,10 @@
import gql from 'graphql-tag'
import gql from 'graphql-tag';
export const eventMinimalInfo = gql`
fragment EventMinimalInfo on events_Event {
id
state
name
designator
startDatetime
finishDatetime
host {
@@ -13,11 +14,12 @@ export const eventMinimalInfo = gql`
}
description
}
`
`;
export const eventFullInfo = gql`
fragment EventFullInfo on events_Event {
designator
id
state
name
host{
alias
@@ -58,4 +60,4 @@ export const eventFullInfo = gql`
}
}
}
`
`;
+10 -4
View File
@@ -1,9 +1,15 @@
import {
eventMinimalInfo,
eventFullInfo
} from './event'
eventFullInfo,
} from './event';
import {
formulaInfo,
plotterInfo,
} from './options';
export {
eventMinimalInfo,
eventFullInfo
}
eventFullInfo,
formulaInfo,
plotterInfo,
};
+22
View File
@@ -0,0 +1,22 @@
import gql from 'graphql-tag';
export const plotterInfo = gql`
fragment PlotterInfo on events_Plotter {
id
ownerId
isTemplate
name
host
repo
moduleName
}
`;
export const formulaInfo = gql`
fragment FormulaInfo on events_Formula {
id
ownerId
isTemplate
name
}
`;
+34 -36
View File
@@ -1,58 +1,56 @@
import React, { Component } from 'react'
import { Route, BrowserRouter, Switch } from 'react-router-dom'
import React, { Component } from 'react';
import { Route, Switch } from 'react-router-dom';
import { MuiPickersUtilsProvider } from 'material-ui-pickers'
import LuxonUtils from 'material-ui-pickers/utils/luxon-utils'
import { MuiPickersUtilsProvider } from 'material-ui-pickers';
import LuxonUtils from 'material-ui-pickers/utils/luxon-utils';
import { getItem } from './utils/local-storage'
import { getItem } from './utils/local-storage';
import TopBar from './Components/TopBar'
import Search from './Components/Search'
import Events from './Components/Events'
import HostedEvents from './Components/HostedEvents'
import EditEvent from './Components/Event/Edit'
import TopBar from './Components/TopBar';
import Search from './Components/Search';
import Events from './Components/Events';
import HostedEvents from './Components/HostedEvents';
import EditEvent from './Components/Event/Edit';
import CreateEvent from './Components/Event/Create';
class App extends Component {
constructor (props) {
super(props)
constructor(props) {
super(props);
this.state = {
user: null
}
user: null,
};
}
async componentDidMount () {
let user = await getItem('user')
async componentDidMount() {
let user = await getItem('user');
if (user !== null && user !== undefined && user !== 'undefined') {
user = JSON.parse(user)
this.setState({ user })
user = JSON.parse(user);
this.setState({ user });
}
}
render () {
let loggedIn
render() {
let loggedIn;
if (this.state.user !== null) {
loggedIn = (<TopBar match={this.props.match} user={this.state.user} />)
loggedIn = (<TopBar match={this.props.match} user={this.state.user} />);
} else {
loggedIn = ''
loggedIn = '';
}
return (
<MuiPickersUtilsProvider utils={LuxonUtils}>
<BrowserRouter basename={this.props.match.path}>
<div>
{loggedIn}
<Switch>
<Route exact path='/' component={Search} />
<Route path='/my' component={Events} />
<Route path='/exact/:slug' component={EditEvent} />
<Route path='/show/:slug' component={EditEvent} />
<Route path='/host' component={HostedEvents} />
</Switch>
</div>
</BrowserRouter>
{loggedIn}
<Switch>
<Route exact path='/events/' component={Search} />
<Route path='/events/my' component={Events} />
<Route path='/events/create' component={CreateEvent} />
<Route path='/events/edit/:slug' component={EditEvent} />
<Route path='/events/show/:slug' component={EditEvent} />
<Route path='/events/host' component={HostedEvents} />
</Switch>
</MuiPickersUtilsProvider>
)
);
}
}
export default App
export default App;
+10 -8
View File
@@ -1,10 +1,12 @@
export const toLocalTime = (epoch) => {
let localDate = new Date(0)
localDate.setUTCSeconds(epoch)
var options = { year: 'numeric', month: 'long', day: '2-digit' }
const localDate = new Date(0);
localDate.setUTCSeconds(epoch);
const options = { year: 'numeric', month: 'long', day: '2-digit' };
return (
localDate.toLocaleDateString(options) +
' at ' +
localDate.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' })
)
}
`${localDate.toLocaleDateString(options)
} at ${
localDate.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' })}`
);
};
export const temporaryFunction = input => input;
+5 -5
View File
@@ -1,9 +1,9 @@
const getItem = async name => window.localStorage.getItem(name)
const setItem = async (name, value) => window.localStorage.setItem(name, value)
const removeItem = async name => window.localStorage.removeItem(name)
const getItem = async name => window.localStorage.getItem(name);
const setItem = async (name, value) => window.localStorage.setItem(name, value);
const removeItem = async name => window.localStorage.removeItem(name);
export {
getItem,
setItem,
removeItem
}
removeItem,
};
+3 -1
View File
@@ -1,3 +1,5 @@
PRESHARED_GATEWAY_KEY=SECRET_STUFF
PORT=3000
DB_USERNAME=example_name
DB_PASSWORD=example_password
@@ -5,4 +7,4 @@ DB_DOMAIN=example.com:1234/example_name
SENTRY_DNS=https://some-val@sentry.io/some-id
TEAMS_ENDPOINT=https://teams-api.advancedalgos.net/graphql/
GATEWAY_ENDPOINT=https://app-api.advancedalgos.net/graphql/
+2 -1
View File
@@ -2,7 +2,8 @@ module.exports = {
parser: 'babel-eslint',
extends: 'airbnb-base',
rules: {
'max-len': ['error', 140, 2],
'no-underscore-dangle': 'off',
'no-param-reassign': 'off'
'no-param-reassign': 'off',
}
};
+748 -299
View File
File diff suppressed because it is too large. Load diff
+1 -3
View File
@@ -26,13 +26,11 @@
},
"dependencies": {
"@sentry/node": "^4.1.1",
"apollo-server-express": "^2.1.0",
"axios": "^0.18.0",
"cors": "^2.8.4",
"dotenv": "^6.0.0",
"express": "^4.16.3",
"express-graphql": "^0.6.12",
"graphql": "^14.0.0",
"graphql-playground-middleware-express": "^1.7.6",
"mongoose": "^5.3.4"
}
}
+29 -18
View File
@@ -1,10 +1,9 @@
import 'dotenv/config';
import express from 'express';
import cors from 'cors';
import graphqlHTTP from 'express-graphql';
import expressPlayground from 'graphql-playground-middleware-express';
import { ApolloServer } from 'apollo-server-express';
import * as Sentry from '@sentry/node';
import schema from './schema';
import wrongPreshared from './errors/notAllowed.json';
const app = express();
@@ -12,27 +11,39 @@ const app = express();
Sentry.init({ dsn: process.env.SENTRY_DNS });
app.use(Sentry.Handlers.requestHandler());
// authorising CORS
app.use(cors());
app.post('/graphql', (req, res, next) => {
if (req.headers.preshared === process.env.PRESHARED_GATEWAY_KEY) {
next();
} else {
res.send(wrongPreshared);
}
});
// Starting the graphql server
app.use('/graphql', graphqlHTTP(req => ({
const server = new ApolloServer({
schema,
context: {
playground: {
settings: {
'editor.theme': 'dark',
'editor.cursorShape': 'line',
},
},
context: ({ req }) => ({
userId: req.headers.userid,
authorization: req.headers.authorization,
},
formatError(err) {
return {
message: err.message,
code: err.originalError && err.originalError.code,
path: err.path,
};
},
})));
}),
formatError: error => ({
code: error.extensions.exception.code,
message: error.message,
path: error.path,
}),
});
// Starting the graphql server
app.get('/playground', expressPlayground({ endpoint: '/graphql' }));
server.applyMiddleware({
app,
cors: true,
});
// Sentry error handling middleware if anything pass through
app.use(Sentry.Handlers.errorHandler());
+2
View File
@@ -2,6 +2,8 @@ import 'dotenv/config';
import mongoose from 'mongoose';
mongoose.connect(`mongodb://${process.env.DB_USERNAME}:${process.env.DB_PASSWORD}@${process.env.DB_DOMAIN}`, { useNewUrlParser: true });
mongoose.set('useCreateIndex', true);
mongoose.set('useFindAndModify', false);
mongoose.Promise = global.Promise;
const db = mongoose.connection;
@@ -4,14 +4,16 @@ export const CANCELLED = 'CANCELLED';
export const RUNNING = 'RUNNING';
export const INTERRUPTED = 'INTERRUPTED';
export const FINISHED = 'FINISHED';
export const ARCHIVED = 'ARCHIVED';
export const EventStatusEnum = [
export const EventStateEnum = [
UNPUBLISHED,
PUBLISHED,
CANCELLED,
RUNNING,
INTERRUPTED,
FINISHED,
ARCHIVED,
];
export default EventStatusEnum;
export default EventStateEnum;
+8
View File
@@ -0,0 +1,8 @@
{
"errors": [
{
"code": 401,
"message": "Wait, you're not supposed to be here, go through the gate as everyone else"
}
]
}
+74 -21
View File
@@ -3,45 +3,98 @@ import Plotter from './plotter';
import Formula from './formula';
import {
UNPUBLISHED,
EventStatusEnum,
} from '../enums/EventStatus';
EventStateEnum,
} from '../enums/EventState';
const { ObjectId } = Schema.Types;
const eventSchema = new Schema({
designator: { type: String, required: true },
status: { type: String, enum: EventStatusEnum, default: UNPUBLISHED },
name: { type: String, required: true },
hostId: { type: String, required: true },
description: String,
startDatetime: { type: Number, required: true },
finishDatetime: { type: Number, required: true },
formula: { type: Schema.Types.ObjectId, ref: Formula.modelName },
plotter: { type: Schema.Types.ObjectId, ref: Plotter.modelName },
state: {
type: String,
enum: EventStateEnum,
default: UNPUBLISHED,
},
name: {
type: String,
required: true,
},
hostId: {
type: String,
required: true,
},
description: {
type: String,
},
startDatetime: {
type: Number,
required: true,
},
finishDatetime: {
type: Number,
required: true,
},
formulaId: {
type: ObjectId,
ref: Formula.modelName,
},
plotterId: {
type: ObjectId,
ref: Plotter.modelName,
},
rules: [{
position: { type: Number, required: true },
title: { type: String, required: true },
description: String,
position: {
type: Number,
required: true,
},
title: {
type: String,
required: true,
},
description: {
type: String,
},
}],
prizes: [{
rank: { type: Number, required: true },
amount: { type: Number, required: true },
rank: {
type: Number,
required: true,
},
amount: {
type: Number,
required: true,
},
additional: [{
condition: String,
amount: { type: Number, required: true },
asset: { type: String, required: true },
amount: {
type: Number,
required: true,
},
asset: {
type: String,
required: true,
},
}],
}],
participants: [{
teamId: { type: String, required: true },
teamId: {
type: String,
required: true,
},
botId: String,
releaseId: String,
}],
});
eventSchema.pre('find', function populate() {
this.populate('formula').populate('plotter');
this.populate('formulaId').populate('plotterId');
});
eventSchema.post('save', (doc, next) => {
doc.populate('formula').populate('plotter').execPopulate().then(() => {
doc.populate('formulaId').populate('plotterId').execPopulate().then(() => {
next();
});
});
eventSchema.post('findOneAndUpdate', (doc, next) => {
doc.populate('formulaId').populate('plotterId').execPopulate().then(() => {
next();
});
});
+12 -3
View File
@@ -1,9 +1,18 @@
import mongoose, { Schema } from 'mongoose';
const formulaSchema = new Schema({
ownerId: { type: String, required: true },
isTemplate: { type: Boolean, default: false },
name: { type: String, required: true },
ownerId: {
type: String,
required: true,
},
isTemplate: {
type: Boolean,
default: false,
},
name: {
type: String,
required: true,
},
});
const Formula = mongoose.model('Formula', formulaSchema);
+24 -6
View File
@@ -1,12 +1,30 @@
import mongoose, { Schema } from 'mongoose';
const plotterSchema = new Schema({
ownerId: { type: String, required: true },
isTemplate: { type: Boolean, default: false },
name: { type: String, required: true },
host: { type: String, required: true },
repo: { type: String, required: true },
moduleName: { type: String, required: true },
ownerId: {
type: String,
required: true,
},
isTemplate: {
type: Boolean,
default: false,
},
name: {
type: String,
required: true,
},
host: {
type: String,
required: true,
},
repo: {
type: String,
required: true,
},
moduleName: {
type: String,
required: true,
},
});
const Plotter = mongoose.model('Plotter', plotterSchema);
-62
View File
@@ -1,62 +0,0 @@
import {
GraphQLNonNull,
GraphQLID,
GraphQLInt,
} from 'graphql';
import {
AuthentificationError,
DatabaseError,
WrongArgumentsError,
} from '../../errors';
import { EventType } from '../types';
import { Event } from '../../models';
const args = {
eventDesignator: { type: new GraphQLNonNull(GraphQLID) },
rank: { type: new GraphQLNonNull(GraphQLInt) },
amount: { type: new GraphQLNonNull(GraphQLInt) },
};
const resolve = (parent, { eventDesignator, rank, amount }, context) => {
const hostId = context.userId;
if (!hostId) {
throw new AuthentificationError();
}
return new Promise((res, rej) => {
Event.findOne({ designator: eventDesignator, hostId }).exec((err, event) => {
if (err) {
rej(err);
return;
}
if (!event) {
rej(new DatabaseError('None of the events you own respond to that designator'));
return;
}
if (event.prizes.some(prize => prize.rank === rank)) {
rej(new WrongArgumentsError('A prize for that rank already exists'));
return;
}
event.prizes.push({
rank,
amount,
});
event.save((error) => {
if (error) {
rej(error);
return;
}
res(event);
});
});
});
};
const mutation = {
addPrize: {
type: EventType,
args,
resolve,
},
};
export default mutation;
-70
View File
@@ -1,70 +0,0 @@
import {
GraphQLNonNull,
GraphQLID,
GraphQLString,
} from 'graphql';
import {
AuthentificationError,
DatabaseError,
WrongArgumentsError,
} from '../../errors';
import { EventType } from '../types';
import { Event } from '../../models';
const args = {
eventDesignator: { type: new GraphQLNonNull(GraphQLID) },
title: { type: new GraphQLNonNull(GraphQLString) },
description: { type: new GraphQLNonNull(GraphQLString) },
};
const resolve = (parent, { eventDesignator, title, description }, context) => {
const hostId = context.userId;
if (!hostId) {
throw new AuthentificationError();
}
return new Promise((res, rej) => {
Event.findOne({ designator: eventDesignator, hostId }).exec((err, event) => {
if (err) {
rej(err);
return;
}
if (!event) {
rej(new DatabaseError('None of the events you own respond to that designator'));
return;
}
if (event.rules.some(rule => rule.title === title)) {
rej(new WrongArgumentsError('A prize for that rank already exists'));
return;
}
const isFree = pos => event.rules.some(rule => rule.pos === pos);
let position = 1;
let shouldGrow = isFree(position);
while (shouldGrow) {
position += 1;
shouldGrow = isFree(position);
}
event.rules.push({
position,
title,
description,
});
event.save((error) => {
if (error) {
rej(error);
return;
}
res(event);
});
});
});
};
const mutation = {
addRule: {
type: EventType,
args,
resolve,
},
};
export default mutation;
@@ -0,0 +1,39 @@
import {
GraphQLNonNull,
GraphQLID,
} from 'graphql';
import { AuthentificationError } from '../../errors';
import { EventType } from '../types';
import { Event } from '../../models';
import EventStateEnum from '../types/enum/EventState';
const args = {
eventId: { type: new GraphQLNonNull(GraphQLID) },
state: { type: EventStateEnum },
};
const resolve = (parent, { eventId: _id, state }, { userId: hostId }) => {
if (!hostId) {
throw new AuthentificationError();
}
return new Promise((res, rej) => {
Event.findOneAndUpdate({ _id, hostId }, { state }, { new: true }, (err, modifiedEvent) => {
if (err) {
rej(err);
return;
}
res(modifiedEvent);
});
});
};
const mutation = {
changeEventState: {
type: EventType,
args,
resolve,
},
};
export default mutation;
@@ -1,56 +0,0 @@
import {
GraphQLNonNull,
GraphQLString,
} from 'graphql';
import { AuthentificationError, DatabaseError } from '../../errors';
import { EventType } from '../types';
import { Event, Formula } from '../../models';
const args = {
eventDesignator: { type: new GraphQLNonNull(GraphQLString) },
name: { type: new GraphQLNonNull(GraphQLString) },
};
const resolve = (parent, { name, eventDesignator }, context) => {
const ownerId = context.userId;
if (!ownerId) {
throw new AuthentificationError();
}
const newFormula = new Formula({ name, ownerId });
return new Promise((res, reject) => {
Event.findOne({ designator: eventDesignator, hostId: ownerId }).exec((err, event) => {
if (err) {
reject(err);
return;
}
if (!event) {
reject(new DatabaseError('None of the events you own respond to that designator'));
return;
}
newFormula.save((error) => {
if (error) {
reject(error);
return;
}
event.formula = newFormula._id;
event.save((eventError) => {
if (eventError) {
reject(eventError);
return;
}
res(event);
});
});
});
});
};
const mutation = {
createAndSetFormula: {
type: EventType,
args,
resolve,
},
};
export default mutation;
@@ -1,65 +0,0 @@
import {
GraphQLNonNull,
GraphQLString,
} from 'graphql';
import { AuthentificationError, DatabaseError } from '../../errors';
import { EventType } from '../types';
import { Event, Plotter } from '../../models';
const args = {
eventDesignator: { type: new GraphQLNonNull(GraphQLString) },
name: { type: new GraphQLNonNull(GraphQLString) },
host: { type: new GraphQLNonNull(GraphQLString) },
repo: { type: new GraphQLNonNull(GraphQLString) },
moduleName: { type: new GraphQLNonNull(GraphQLString) },
};
const resolve = (parent, {
name, host, repo, moduleName, eventDesignator,
}, context) => {
const ownerId = context.userId;
if (!ownerId) {
throw new AuthentificationError();
}
const newPlotter = new Plotter({
name, host, repo, moduleName, ownerId,
});
return new Promise((res, rej) => {
Event.findOne({ designator: eventDesignator, hostId: ownerId }).exec((err, event) => {
if (err) {
rej(err);
return;
}
if (!event) {
rej(new DatabaseError('None of the events you own respond to that designator'));
return;
}
newPlotter.save((error) => {
if (error) {
rej(error);
return;
}
event.plotter = newPlotter._id;
event.save((eventError) => {
if (eventError) {
rej(eventError);
return;
}
res(event);
});
});
});
});
};
const mutation = {
createAndSetPlotter: {
type: EventType,
args,
resolve,
},
};
export default mutation;
@@ -0,0 +1,37 @@
import { AuthentificationError } from '../../errors';
import { EventType } from '../types';
import { Event } from '../../models';
import { EventInputType } from '../types/input';
export const args = {
event: { type: EventInputType },
};
const resolve = (parent, { event }, { userId: hostId }) => {
if (!hostId) {
throw new AuthentificationError();
}
event.hostId = hostId;
const newEvent = new Event(event);
return new Promise((res, rej) => {
newEvent.save((err) => {
if (err) {
rej(err);
return;
}
res(newEvent);
});
});
};
const mutation = {
createEvent: {
type: EventType,
args,
resolve,
},
};
export default mutation;
+7 -8
View File
@@ -1,21 +1,20 @@
import {
GraphQLNonNull,
GraphQLString,
} from 'graphql';
import { AuthentificationError } from '../../errors';
import { FormulaType } from '../types';
import { Formula } from '../../models';
import { FormulaInputType } from '../types/input';
const args = {
name: { type: new GraphQLNonNull(GraphQLString) },
formula: { type: FormulaInputType },
};
const resolve = (parent, { name }, context) => {
const ownerId = context.userId;
const resolve = (parent, { formula }, { userId: ownerId }) => {
if (!ownerId) {
throw new AuthentificationError();
}
const newFormula = new Formula({ name, ownerId });
formula.ownerId = ownerId;
const newFormula = new Formula(formula);
return new Promise((res, rej) => {
newFormula.save((err) => {
if (err) {
+7 -15
View File
@@ -1,28 +1,20 @@
import {
GraphQLNonNull,
GraphQLString,
} from 'graphql';
import { AuthentificationError } from '../../errors';
import { PlotterType } from '../types';
import { Plotter } from '../../models';
import { PlotterInputType } from '../types/input';
const args = {
name: { type: new GraphQLNonNull(GraphQLString) },
host: { type: new GraphQLNonNull(GraphQLString) },
repo: { type: new GraphQLNonNull(GraphQLString) },
moduleName: { type: new GraphQLNonNull(GraphQLString) },
plotter: { type: PlotterInputType },
};
const resolve = (parent, {
name, host, repo, moduleName,
}, context) => {
const ownerId = context.userId;
const resolve = (parent, { plotter }, { userId: ownerId }) => {
if (!ownerId) {
throw new AuthentificationError();
}
const newPlotter = new Plotter({
name, host, repo, moduleName, ownerId,
});
plotter.ownerId = ownerId;
const newPlotter = new Plotter(plotter);
return new Promise((res, reject) => {
newPlotter.save((err) => {
if (err) {
+8 -33
View File
@@ -1,54 +1,29 @@
import {
GraphQLNonNull,
GraphQLID,
GraphQLInt,
GraphQLString,
} from 'graphql';
import { AuthentificationError, DatabaseError } from '../../errors';
import { AuthentificationError } from '../../errors';
import { EventType } from '../types';
import { Event } from '../../models';
import { EventInputType } from '../types/input';
const args = {
designator: { type: new GraphQLNonNull(GraphQLID) },
name: { type: GraphQLString },
description: { type: GraphQLString },
startDatetime: { type: GraphQLInt },
finishDatetime: { type: GraphQLInt },
formulaId: { type: GraphQLString },
plotterId: { type: GraphQLString },
eventId: { type: new GraphQLNonNull(GraphQLID) },
event: { type: EventInputType },
};
const resolve = (parent, {
designator, name, description, startDatetime, finishDatetime, formulaId, plotterId,
}, context) => {
const hostId = context.userId;
const resolve = (parent, { eventId: _id, event }, { userId: hostId }) => {
if (!hostId) {
throw new AuthentificationError();
}
return new Promise((res, rej) => {
Event.findOne({ designator, hostId }).exec((err, event) => {
Event.findOneAndUpdate({ _id, hostId }, event, { new: true }, (err, modifiedEvent) => {
if (err) {
rej(err);
return;
}
if (!event) {
rej(new DatabaseError('None of the events you own respond to that designator'));
return;
}
event.name = name || event.name;
event.description = description || event.description;
event.startDatetime = startDatetime || event.startDatetime;
event.finishDatetime = finishDatetime || event.finishDatetime;
event.formula = formulaId || event.formula;
event.plotter = plotterId || event.plotter;
event.save((error) => {
if (error) {
rej(error);
return;
}
res(event);
});
res(modifiedEvent);
});
});
};
+12 -18
View File
@@ -1,7 +1,6 @@
import {
GraphQLNonNull,
GraphQLID,
GraphQLString,
} from 'graphql';
import axios from 'axios';
import {
@@ -11,45 +10,40 @@ import {
} from '../../errors';
import { EventType } from '../types';
import { Event } from '../../models';
import { ParticipantInputType } from '../types/input';
const args = {
eventDesignator: { type: new GraphQLNonNull(GraphQLID) },
teamId: { type: new GraphQLNonNull(GraphQLString) },
botId: { type: GraphQLString },
releaseId: { type: GraphQLString },
eventId: { type: new GraphQLNonNull(GraphQLID) },
participant: { type: ParticipantInputType },
};
const resolve = (parent, {
eventDesignator, teamId, botId, releaseId,
}, context) => {
const userid = context.userId;
if (!userid) {
const resolve = (parent,
{ eventId: _id, participant: { teamId, botId, releaseId } },
{ userId, authorization }) => {
if (!userId) {
throw new AuthentificationError();
}
return new Promise((res, rej) => {
axios({
url: process.env.TEAMS_ENDPOINT,
url: process.env.GATEWAY_ENDPOINT,
method: 'post',
data: {
query: `
{
teamsByRole{
teams_TeamsByRole{
id
}
}
`,
},
headers: {
userid,
authorization: context.authorization,
},
headers: { authorization },
}).then(
(result) => {
if (!result.data.data.teamsByRole.some(team => team.id === teamId)) {
rej(new WrongArgumentsError('You are not eligible to register this team'));
rej(new WrongArgumentsError('You are not eligible to edit this team'));
return;
}
Event.findOne({ designator: eventDesignator }).exec((err, event) => {
Event.findOne({ _id }).exec((err, event) => {
if (err) {
rej(err);
return;
-56
View File
@@ -1,56 +0,0 @@
import {
GraphQLNonNull,
GraphQLID,
GraphQLInt,
} from 'graphql';
import { AuthentificationError, DatabaseError } from '../../errors';
import { EventType } from '../types';
import { Event } from '../../models';
const args = {
eventDesignator: { type: new GraphQLNonNull(GraphQLID) },
rank: { type: new GraphQLNonNull(GraphQLInt) },
amount: { type: GraphQLInt },
};
const resolve = (parent, { eventDesignator, rank, amount }, context) => {
const hostId = context.userId;
if (!hostId) {
throw new AuthentificationError();
}
return new Promise((res, rej) => {
Event.findOne({ designator: eventDesignator, hostId }).exec((err, event) => {
if (err) {
rej(err);
return;
}
if (!event) {
rej(new DatabaseError('None of the events you own respond to that designator'));
return;
}
const prizeIndex = event.prizes.findIndex(prize => prize.rank === rank);
if (!prizeIndex) {
rej(new DatabaseError('There is no prize for that index'));
return;
}
event.prizes[prizeIndex].amount = amount || event.prizes[prizeIndex].amount;
event.save((error) => {
if (error) {
rej(error);
return;
}
res(event);
});
});
});
};
const mutation = {
editPrize: {
type: EventType,
args,
resolve,
},
};
export default mutation;
-64
View File
@@ -1,64 +0,0 @@
import {
GraphQLNonNull,
GraphQLID,
GraphQLString,
} from 'graphql';
import { AuthentificationError, DatabaseError, WrongArgumentsError } from '../../errors';
import { EventType } from '../types';
import { Event } from '../../models';
const args = {
eventDesignator: { type: new GraphQLNonNull(GraphQLID) },
title: { type: new GraphQLNonNull(GraphQLString) },
newtitle: { type: GraphQLString },
description: { type: GraphQLString },
};
const resolve = (parent, {
eventDesignator, title, newtitle, description,
}, context) => {
const hostId = context.userId;
if (!hostId) {
throw new AuthentificationError();
}
return new Promise((res, rej) => {
Event.findOne({ designator: eventDesignator, hostId }).exec((err, event) => {
if (err) {
rej(err);
return;
}
if (!event) {
rej(new DatabaseError('None of the events you own respond to that designator'));
return;
}
const ruleIndex = event.rules.findIndex(rule => rule.title === title);
if (!ruleIndex) {
rej(new DatabaseError('There is no rule with that title'));
return;
}
event.rules[ruleIndex].description = description || event.rules[ruleIndex].description;
if (event.rules.some(rule => rule.title === newtitle)) {
rej(new WrongArgumentsError('There is already a rule using your new title'));
return;
}
event.rules[ruleIndex].title = newtitle || event.rules[ruleIndex].title;
event.save((error) => {
if (error) {
rej(error);
return;
}
res(event);
});
});
});
};
const mutation = {
editRule: {
type: EventType,
args,
resolve,
},
};
export default mutation;
-52
View File
@@ -1,52 +0,0 @@
import {
GraphQLNonNull,
GraphQLInt,
GraphQLString,
} from 'graphql';
import { AuthentificationError } from '../../errors';
import { EventType } from '../types';
import { Event } from '../../models';
import { slugify } from '../../utils/functions';
const args = {
name: { type: new GraphQLNonNull(GraphQLString) },
description: { type: new GraphQLNonNull(GraphQLString) },
startDatetime: { type: new GraphQLNonNull(GraphQLInt) },
finishDatetime: { type: new GraphQLNonNull(GraphQLInt) },
};
const resolve = (parent, {
name, description, startDatetime, finishDatetime,
}, context) => {
const hostId = context.userId;
if (!hostId) {
throw new AuthentificationError();
}
const newEvent = new Event({
hostId,
name,
description,
startDatetime,
finishDatetime,
});
newEvent.designator = `${slugify(newEvent.name)}-${newEvent._id}`;
return new Promise((res, rej) => {
newEvent.save((err) => {
if (err) {
rej(err);
return;
}
res(newEvent);
});
});
};
const mutation = {
hostEvent: {
type: EventType,
args,
resolve,
},
};
export default mutation;
+11 -17
View File
@@ -2,7 +2,6 @@ import 'dotenv/config';
import {
GraphQLNonNull,
GraphQLID,
GraphQLString,
} from 'graphql';
import axios from 'axios';
import {
@@ -12,45 +11,40 @@ import {
} from '../../errors';
import { EventType } from '../types';
import { Event } from '../../models';
import { ParticipantInputType } from '../types/input';
const args = {
designator: { type: new GraphQLNonNull(GraphQLID) },
teamId: { type: new GraphQLNonNull(GraphQLString) },
botId: { type: GraphQLString },
releaseId: { type: GraphQLString },
eventId: { type: new GraphQLNonNull(GraphQLID) },
participant: { type: ParticipantInputType },
};
const resolve = (parent, {
designator, teamId, botId, releaseId,
}, context) => {
const userid = context.userId;
if (!userid) {
const resolve = (parent,
{ eventId: _id, participant: { teamId, botId, releaseId } },
{ userId, authorization }) => {
if (!userId) {
throw new AuthentificationError();
}
return new Promise((res, rej) => {
axios({
url: process.env.TEAMS_ENDPOINT,
url: process.env.GATEWAY_ENDPOINT,
method: 'post',
data: {
query: `
{
teamsByRole{
teams_TeamsByRole{
id
}
}
`,
},
headers: {
userid,
authorization: context.authorization,
},
headers: { authorization },
}).then(
(result) => {
if (!result.data.data.teamsByRole.some(team => team.id === teamId)) {
rej(new WrongArgumentsError('You are not eligible to register this team'));
return;
}
Event.findOne({ designator }).exec((err, event) => {
Event.findOne({ _id }).exec((err, event) => {
if (err) {
rej(err);
return;
@@ -1,60 +0,0 @@
import {
GraphQLNonNull,
GraphQLID,
GraphQLInt,
} from 'graphql';
import { AuthentificationError, DatabaseError } from '../../errors';
import { isBetween } from '../../utils/functions';
import { EventType } from '../types';
import { Event } from '../../models';
const args = {
eventDesignator: { type: new GraphQLNonNull(GraphQLID) },
fromPosition: { type: new GraphQLNonNull(GraphQLInt) },
toPosition: { type: new GraphQLNonNull(GraphQLInt) },
};
const resolve = (parent, { eventDesignator, fromPosition, toPosition }, context) => {
const hostId = context.userId;
if (!hostId) {
throw new AuthentificationError();
}
return new Promise((res, rej) => {
Event.findOne({ designator: eventDesignator, hostId: context.userId }).exec((err, event) => {
if (err) {
rej(err);
return;
}
if (!event) {
rej(new DatabaseError('None of the events you own respond to that designator'));
return;
}
const delta = fromPosition > toPosition ? 1 : -1;
event.rules.forEach((part) => {
if (part.position === fromPosition) {
part.position = toPosition;
} else if (isBetween(part.position, fromPosition, toPosition)) {
part.position += delta;
}
});
event.save((error) => {
if (error) {
rej(error);
return;
}
res(event);
});
});
});
};
const mutation = {
reorderRules: {
type: EventType,
args,
resolve,
},
};
export default mutation;
+4 -16
View File
@@ -2,36 +2,24 @@ import {
GraphQLObjectType,
} from 'graphql';
import HostEventMutation from './HostEvent';
import CreateEventMutation from './CreateEvent';
import EditEventMutation from './EditEvent';
import RegisterToEventMutation from './RegisterToEvent';
import EditParticipantMutation from './EditParticipant';
import AddRuleMutation from './AddRule';
import EditRuleMutation from './EditRule';
import ReorderRulesMutation from './ReorderRules';
import AddPrizeMutation from './AddPrize';
import EditPrizeMutation from './EditPrize';
import CreateFormulaMutation from './CreateFormula';
import CreateAndSetFormulaMutation from './CreateAndSetFormula';
import CreatePlotterMutation from './CreatePlotter';
import CreateAndSetPlotterMutation from './CreateAndSetPlotter';
import ChangeEventStateMutation from './ChangeEventState';
const Mutation = new GraphQLObjectType({
name: 'Mutation',
fields: Object.assign(
HostEventMutation,
CreateEventMutation,
EditEventMutation,
RegisterToEventMutation,
EditParticipantMutation,
AddRuleMutation,
EditRuleMutation,
ReorderRulesMutation,
AddPrizeMutation,
EditPrizeMutation,
CreateFormulaMutation,
CreateAndSetFormulaMutation,
CreatePlotterMutation,
CreateAndSetPlotterMutation,
ChangeEventStateMutation,
),
});
+4 -4
View File
@@ -7,17 +7,17 @@ import { EventType } from '../types';
import { Event } from '../../models';
const args = {
designator: { type: new GraphQLNonNull(GraphQLID) },
eventId: { type: new GraphQLNonNull(GraphQLID) },
};
const resolve = (parent, { designator }) => new Promise((res, rej) => {
Event.findOne({ designator }).exec((err, event) => {
const resolve = (parent, { eventId: _id }) => new Promise((res, rej) => {
Event.findOne({ _id }).exec((err, event) => {
if (err) {
rej(err);
return;
}
if (!event) {
rej(new DatabaseError('None of the events respond to that designator'));
rej(new DatabaseError('None of the events respond to that id'));
return;
}
res(event);
+2
View File
@@ -4,6 +4,7 @@ import {
} from 'graphql';
import { EventType } from '../types';
import { Event } from '../../models';
import { UNPUBLISHED, ARCHIVED } from '../../enums/EventState';
const args = {
minDate: { type: GraphQLInt },
@@ -12,6 +13,7 @@ const args = {
const resolve = (parent, { minDate, maxDate }) => Event.find(
Object.assign(
{ state: { $nin: [UNPUBLISHED, ARCHIVED] } },
minDate || maxDate
? {
startDatetime:
+2 -1
View File
@@ -5,6 +5,7 @@ import {
} from 'graphql';
import { EventType } from '../types';
import { Event } from '../../models';
import { UNPUBLISHED, ARCHIVED } from '../../enums/EventState';
const args = {
hostId: { type: GraphQLString },
@@ -14,7 +15,7 @@ const args = {
const resolve = (parent, { hostId, minDate, maxDate }, context) => Event.find(
Object.assign(
hostId ? { hostId } : { hostId: context.userId },
hostId ? { hostId, state: { $nin: [UNPUBLISHED, ARCHIVED] } } : { hostId: context.userId },
minDate || maxDate
? {
startDatetime:
+6 -1
View File
@@ -6,6 +6,7 @@ import {
} from 'graphql';
import { EventType } from '../types';
import { Event } from '../../models';
import { UNPUBLISHED, ARCHIVED } from '../../enums/EventState';
const args = {
teamId: { type: new GraphQLNonNull(GraphQLString) },
@@ -15,7 +16,11 @@ const args = {
const resolve = (parent, { teamId, minDate, maxDate }) => Event.find(
Object.assign(
{ participants: { $elemMatch: { teamId } } },
{
participants: { $elemMatch: { teamId } },
state: { $nin: [UNPUBLISHED, ARCHIVED] },
},
minDate || maxDate
? {
startDatetime:
+5 -3
View File
@@ -1,15 +1,17 @@
import {
GraphQLObjectType,
GraphQLNonNull,
GraphQLString,
GraphQLInt,
} from 'graphql';
const AdditionalPrizeType = new GraphQLObjectType({
name: 'OtherPrize',
name: 'AdditionalPrize',
description: 'Non algo complementary prize',
fields: () => ({
condition: { type: GraphQLString },
amount: { type: GraphQLInt },
asset: { type: GraphQLString },
amount: { type: new GraphQLNonNull(GraphQLInt) },
asset: { type: new GraphQLNonNull(GraphQLString) },
}),
});
+6 -3
View File
@@ -12,11 +12,14 @@ import {
ParticipantType,
PrizeType,
} from './index';
import EventStateEnumType from './enum/EventState';
const EventType = new GraphQLObjectType({
name: 'Event',
description: 'Everything you need to know about an event',
fields: () => ({
designator: { type: GraphQLID },
id: { type: GraphQLID },
state: { type: EventStateEnumType },
name: { type: GraphQLString },
hostId: { type: GraphQLString },
description: { type: GraphQLString },
@@ -25,13 +28,13 @@ const EventType = new GraphQLObjectType({
formula: {
type: FormulaType,
resolve(parent) {
return parent.formula;
return parent.formulaId;
},
},
plotter: {
type: PlotterType,
resolve(parent) {
return parent.plotter;
return parent.plotterId;
},
},
rules: {
+1
View File
@@ -6,6 +6,7 @@ import {
const FormulaType = new GraphQLObjectType({
name: 'Formula',
description: 'For now it\'s simplay a named field',
fields: () => ({
id: { type: GraphQLString },
ownerId: { type: GraphQLString },
+1
View File
@@ -5,6 +5,7 @@ import {
const ParticipantType = new GraphQLObjectType({
name: 'Participant',
description: 'Informations about the participant of an event',
fields: () => ({
teamId: { type: GraphQLString },
botId: { type: GraphQLString },
+1
View File
@@ -6,6 +6,7 @@ import {
const PlotterType = new GraphQLObjectType({
name: 'Plotter',
description: 'Will soon change in order to use contained plotter objects',
fields: () => ({
id: { type: GraphQLString },
ownerId: { type: GraphQLString },
+4 -2
View File
@@ -2,14 +2,16 @@ import {
GraphQLObjectType,
GraphQLList,
GraphQLInt,
GraphQLNonNull,
} from 'graphql';
import { AdditionalPrizeType } from './index';
const PrizeType = new GraphQLObjectType({
name: 'Prize',
description: 'Prize, by default in algos',
fields: () => ({
rank: { type: GraphQLInt },
amount: { type: GraphQLInt },
rank: { type: new GraphQLNonNull(GraphQLInt) },
amount: { type: new GraphQLNonNull(GraphQLInt) },
additional: {
type: new GraphQLList(AdditionalPrizeType),
resolve(parent) {
+1
View File
@@ -6,6 +6,7 @@ import {
const RuleType = new GraphQLObjectType({
name: 'Rule',
description: 'Textual rules of an event',
fields: () => ({
position: { type: GraphQLInt },
title: { type: GraphQLString },
@@ -0,0 +1,19 @@
import {
GraphQLEnumType,
} from 'graphql';
import { EventStateEnum } from '../../../enums/EventState';
const values = {};
EventStateEnum.forEach((EventState) => {
values[EventState] = { value: EventState };
});
const EventStateEnumType = new GraphQLEnumType({
name: 'EventStateEnum',
values,
});
export {
EventStateEnumType as default,
};
@@ -0,0 +1,18 @@
import {
GraphQLInputObjectType,
GraphQLNonNull,
GraphQLString,
GraphQLInt,
} from 'graphql';
const Type = new GraphQLInputObjectType({
name: 'AdditionalPrizeInput',
description: 'Payload for formula input',
fields: () => ({
condition: { type: GraphQLString },
amount: { type: new GraphQLNonNull(GraphQLInt) },
asset: { type: new GraphQLNonNull(GraphQLString) },
}),
});
export default Type;
+25
View File
@@ -0,0 +1,25 @@
import {
GraphQLString,
GraphQLInt,
GraphQLInputObjectType,
GraphQLList,
} from 'graphql';
import InputPrizeType from './Prize';
import InputRuleType from './Rule';
const Type = new GraphQLInputObjectType({
name: 'EventInput',
description: 'Payload for event input',
fields: () => ({
name: { type: GraphQLString },
description: { type: GraphQLString },
startDatetime: { type: GraphQLInt },
finishDatetime: { type: GraphQLInt },
formulaId: { type: GraphQLString },
plotterId: { type: GraphQLString },
prizes: { type: new GraphQLList(InputPrizeType) },
rules: { type: new GraphQLList(InputRuleType) },
}),
});
export default Type;
+15
View File
@@ -0,0 +1,15 @@
import {
GraphQLNonNull,
GraphQLString,
GraphQLInputObjectType,
} from 'graphql';
const Type = new GraphQLInputObjectType({
name: 'FormulaInput',
description: 'Payload for formula input',
fields: () => ({
name: { type: new GraphQLNonNull(GraphQLString) },
}),
});
export default Type;
@@ -0,0 +1,17 @@
import {
GraphQLInputObjectType,
GraphQLString,
GraphQLNonNull,
} from 'graphql';
const Type = new GraphQLInputObjectType({
name: 'ParticipantInput',
description: 'Payload for formula input',
fields: () => ({
teamId: { type: new GraphQLNonNull(GraphQLString) },
botId: { type: GraphQLString },
releaseId: { type: GraphQLString },
}),
});
export default Type;
+18
View File
@@ -0,0 +1,18 @@
import {
GraphQLNonNull,
GraphQLString,
GraphQLInputObjectType,
} from 'graphql';
const Type = new GraphQLInputObjectType({
name: 'PlotterInput',
description: 'Payload for plotter input',
fields: () => ({
name: { type: new GraphQLNonNull(GraphQLString) },
host: { type: GraphQLString },
repo: { type: GraphQLString },
moduleName: { type: GraphQLString },
}),
});
export default Type;
+21
View File
@@ -0,0 +1,21 @@
import {
GraphQLInputObjectType,
GraphQLList,
GraphQLInt,
GraphQLNonNull,
} from 'graphql';
import InputAdditionalPrizeType from './AdditionalPrize';
const Type = new GraphQLInputObjectType({
name: 'PrizeInput',
description: 'Payload for formula input',
fields: () => ({
rank: { type: new GraphQLNonNull(GraphQLInt) },
amount: { type: new GraphQLNonNull(GraphQLInt) },
additional: {
type: new GraphQLList(InputAdditionalPrizeType),
},
}),
});
export default Type;
+18
View File
@@ -0,0 +1,18 @@
import {
GraphQLNonNull,
GraphQLString,
GraphQLInt,
GraphQLInputObjectType,
} from 'graphql';
const Type = new GraphQLInputObjectType({
name: 'RuleInput',
description: 'Payload for rule input',
fields: () => ({
position: { type: GraphQLInt },
title: { type: new GraphQLNonNull(GraphQLString) },
description: { type: GraphQLString },
}),
});
export default Type;
+17
View File
@@ -0,0 +1,17 @@
import PlotterInputType from './Plotter';
import RuleInputType from './Rule';
import PrizeInputType from './Prize';
import FormulaInputType from './Formula';
import EventInputType from './Event';
import AdditionalPrizeInputType from './AdditionalPrize';
import ParticipantInputType from './Participant';
export {
PlotterInputType,
RuleInputType,
PrizeInputType,
FormulaInputType,
EventInputType,
AdditionalPrizeInputType,
ParticipantInputType,
};