Merge branch 'develop'

This commit is contained in:
Luis Fernando Molina committed 2018-09-29 19:59:15 +02:00
commit 2d57623abf
46 files changed
+2068 -292

No files matched your search

+1 -1
View File
@@ -20,7 +20,7 @@ App.js
| | |
| | |- UserTabs
| | | |
| | | |- Tab 1 - UserUpdate
| | | |- Tab 1 - ProfileSheet
| | | |
| | | |- Tab 2 - ManageImages
| |
+71
View File
@@ -4628,6 +4628,11 @@
"schema-utils": "0.3.0"
}
},
"file-type": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-8.1.0.tgz",
"integrity": "sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ=="
},
"filename-regex": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
@@ -4647,6 +4652,44 @@
"resolved": "https://registry.npmjs.org/filesize/-/filesize-3.5.11.tgz",
"integrity": "sha512-ZH7loueKBoDb7yG9esn1U+fgq7BzlzW6NRi5/rMdxIZ05dj7GFD/Xc5rq2CDt5Yq86CyfSYVyx4242QQNZbx1g=="
},
"filestack-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/filestack-js/-/filestack-js-1.5.1.tgz",
"integrity": "sha512-NXYZhKl0JySNNpQNWtKdyMfQAiMw6VF8Mx+XWHGg+gh3By3ITjR0wTorjM02CVr/6Od/DXQCN1e+6np1Zex9Nw==",
"requires": {
"abab": "1.0.4",
"bowser": "1.9.4",
"file-type": "8.1.0",
"filestack-loader": "3.0.4",
"is-svg": "3.0.0",
"isutf8": "2.0.2",
"mime-types": "2.1.20",
"spark-md5": "3.0.0",
"superagent": "3.8.3",
"tcomb-validation": "3.4.1",
"tslib": "1.9.3"
},
"dependencies": {
"is-svg": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz",
"integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==",
"requires": {
"html-comment-regex": "1.1.1"
}
}
}
},
"filestack-loader": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/filestack-loader/-/filestack-loader-3.0.4.tgz",
"integrity": "sha512-b6uOCWHd1gM0+5KBA1rA4qfEgTqyTr5umLM4bBWT4z98WUwxa6KzCiq+z0VnR4rN+NCx6kyZ/wLXjGcPU32TxQ=="
},
"filestack-react": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/filestack-react/-/filestack-react-2.0.0.tgz",
"integrity": "sha512-+lOqPx2XYsvm3pJutjlDTyG8fdrJAefN0QLi8crJfwI1dJffOjK84dnQJHQ9aQzxF37A1cHI8ZbPscv7w6bRTA=="
},
"fill-range": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
@@ -6516,6 +6559,11 @@
"handlebars": "4.0.11"
}
},
"isutf8": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/isutf8/-/isutf8-2.0.2.tgz",
"integrity": "sha512-9lNbG6k+PE6vuFnPTHjhtX79/LDMQrXoFx1MOEjXXCyqFCSahWKAzuAb9G5ct+lfS12aQxNmC0tiZuyujvr4Uw=="
},
"iterall": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz",
@@ -10805,6 +10853,11 @@
"resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
"integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM="
},
"spark-md5": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.0.tgz",
"integrity": "sha1-NyIifFTi+vJLHcbZM8wUTm9xv+8="
},
"spdx-correct": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz",
@@ -11170,6 +11223,19 @@
"resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz",
"integrity": "sha1-mTcqXJmb8t8WCvwNdL7U9HlIzSI="
},
"tcomb": {
"version": "3.2.27",
"resolved": "https://registry.npmjs.org/tcomb/-/tcomb-3.2.27.tgz",
"integrity": "sha512-XWdJW7F/M3YzXhDEUP8ycmNWoYymBtsHwCHoda0YF44RthJsls95TqDrmpAlC1sB/KXaCvkdBlcNRq+AaV6klA=="
},
"tcomb-validation": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/tcomb-validation/-/tcomb-validation-3.4.1.tgz",
"integrity": "sha512-urVVMQOma4RXwiVCa2nM2eqrAomHROHvWPuj6UkDGz/eb5kcy0x6P0dVt6kzpUZtYMNoAqJLWmz1BPtxrtjtrA==",
"requires": {
"tcomb": "3.2.27"
}
},
"term-size": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz",
@@ -11340,6 +11406,11 @@
"resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
"integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM="
},
"tslib": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
"integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ=="
},
"tty-browserify": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
+2
View File
@@ -12,6 +12,8 @@
"apollo-link-error": "^1.1.0",
"apollo-link-http": "^1.5.4",
"auth0-lock": "^11.9.0",
"filestack-js": "^1.5.1",
"filestack-react": "^2.0.0",
"graphql": "^14.0.0",
"graphql-tag": "^2.9.2",
"react": "^16.4.2",
+1 -10
View File
@@ -32,6 +32,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<link href="https://fonts.googleapis.com/css?family=Saira+Condensed:300,600|Saira:300,600&amp;subset=latin-ext,vietnamese" rel="stylesheet">
<!-- font awesome -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" integrity="sha384-DNOHZ68U8hZfKXOrtjWvjxusGo9WQnrNx2sqG0tfsghAvtVlRW3tvkXWZh58N9jp" crossorigin="anonymous">
<!-- default font of Material-UI -->
@@ -52,15 +53,5 @@
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
+8 -11
View File
@@ -11,7 +11,8 @@ import { Route, BrowserRouter, Switch } from 'react-router-dom'
// Material UI
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles'
import { MuiThemeProvider } from '@material-ui/core/styles'
import theme from './theme'
// Components
@@ -26,11 +27,16 @@ import Modules from './components/Modules'
import Contact from './components/Contact'
import Logout from './components/Logout'
import Post from './components/Post'
import Footer from './components/Footer'
// import Footer from './components/Footer'
import Callback from './components/Callback'
import Auth from './auth/Auth'
import {
// NavBar,
Footer
} from './views'
// Apollo Client Setup
const httpLink = new HttpLink({ uri: 'http://localhost:4000/graphql', changeOrigin: true })
@@ -70,15 +76,6 @@ export const client = new ApolloClient({
export const auth = new Auth(result => console.log('auth result', result), client)
/* Here we change the default Material UI theme for Advanced Algos brand colors. */
const theme = createMuiTheme({
palette: {
primary: { main: '#303036' }, // DARK.
secondary: { main: '#CC5835' } // RUSTED_RED.
}
})
class App extends Component {
render () {
return (
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 120 24"><defs><style>.cls-1,.cls-3{fill:none;}.cls-2{clip-path:url(#clip-path);}.cls-3{stroke:#2a96ff;stroke-miterlimit:10;stroke-width:0.5px;}.cls-4{fill:#fff;}.cls-5{fill:#e3493c;}</style><clipPath id="clip-path"><rect class="cls-1" x="272.54" y="79.59" width="600" height="600"/></clipPath></defs><title>aa-logo-dark</title><g id="Layer_1" data-name="Layer 1"><g class="cls-2"><circle class="cls-3" cx="338.14" cy="263.28" r="277.97"/></g></g><g id="Layer_4" data-name="Layer 4"><path class="cls-4" d="M27.67,15.74l-.19-1.58H26.29l-.2,1.58H24.51L25.7,7.79h2.39l1.19,8Zm-.75-6.39h-.08l-.4,3.41h.89Z"/><path class="cls-4" d="M32.15,7.79h1.93a2.39,2.39,0,0,1,1.46.35,1.68,1.68,0,0,1,.54,1.11,21,21,0,0,1,.1,2.52,20.93,20.93,0,0,1-.1,2.51,1.68,1.68,0,0,1-.54,1.11,2.39,2.39,0,0,1-1.46.35H32.15Zm1.93,6.51a.46.46,0,0,0,.37-.12,1.19,1.19,0,0,0,.13-.6c0-.32,0-.93,0-1.81s0-1.5,0-1.82a1.19,1.19,0,0,0-.13-.6.46.46,0,0,0-.37-.12h-.36V14.3Z"/><path class="cls-4" d="M39.94,15.74,38.87,7.79h1.59l.66,6.31h.12l.61-6.31h1.57l-1.07,8Z"/><path class="cls-4" d="M48.8,15.74l-.19-1.58H47.42l-.2,1.58H45.64l1.19-7.95h2.39l1.19,8Zm-.75-6.39H48l-.4,3.41h.89Z"/><path class="cls-4" d="M56.06,15.74l-1.23-4h0v4h-1.5V7.79h1.47l1.13,3.61h.06V7.79h1.51v8Z"/><path class="cls-4" d="M63.14,15.77a3.11,3.11,0,0,1-.59.06,2.06,2.06,0,0,1-1.36-.37,1.94,1.94,0,0,1-.58-1.19,17.1,17.1,0,0,1-.13-2.5,14.22,14.22,0,0,1,.15-2.5,1.94,1.94,0,0,1,.58-1.2,2,2,0,0,1,1.34-.37,4.21,4.21,0,0,1,.62,0,1.86,1.86,0,0,1,.45.12V9.2a5.77,5.77,0,0,0-.78-.06.77.77,0,0,0-.55.15,1.22,1.22,0,0,0-.18.64c0,.33,0,.94,0,1.84s0,1.5,0,1.83a1.22,1.22,0,0,0,.18.64.77.77,0,0,0,.55.15,4.74,4.74,0,0,0,.8-.06v1.29A1.56,1.56,0,0,1,63.14,15.77Z"/><path class="cls-4" d="M66.59,15.74V7.79h3.19V9.23h-1.6V11h1.41v1.45H68.18V14.3h1.6v1.44Z"/><path class="cls-4" d="M72.79,7.79h1.92a2.4,2.4,0,0,1,1.47.35,1.67,1.67,0,0,1,.53,1.11,20.46,20.46,0,0,1,.11,2.52,20.38,20.38,0,0,1-.11,2.51,1.67,1.67,0,0,1-.53,1.11,2.4,2.4,0,0,1-1.47.35H72.79Zm1.92,6.51a.48.48,0,0,0,.38-.12,1.19,1.19,0,0,0,.13-.6c0-.32,0-.93,0-1.81s0-1.5,0-1.82a1.19,1.19,0,0,0-.13-.6.48.48,0,0,0-.38-.12h-.35V14.3Z"/><path class="cls-5" d="M85.6,15.74l-.91-2.31H80.93L80,15.74h-.76l3.11-7.95h.89l3.12,8ZM82.84,8.66h-.06l-1.61,4.08h3.27Z"/><path class="cls-5" d="M88.44,15.74V7.79h.74V15H93v.72Z"/><path class="cls-5" d="M97.86,12.24v-.68h2.7v4c-.37.06-.8.12-1.26.16s-.87.06-1.22.06a5.68,5.68,0,0,1-2.14-.3A1.71,1.71,0,0,1,95,14.4a9.76,9.76,0,0,1-.26-2.63A9.85,9.85,0,0,1,95,9.13,1.71,1.71,0,0,1,96,8a5.91,5.91,0,0,1,2.13-.29c.38,0,.81,0,1.27.06s.86.1,1.18.16v.66a13.61,13.61,0,0,0-2-.19,8.76,8.76,0,0,0-2,.16,1.21,1.21,0,0,0-.79.85,8.45,8.45,0,0,0-.23,2.37A10.48,10.48,0,0,0,95.66,14a1.27,1.27,0,0,0,.7.91,4.41,4.41,0,0,0,1.72.24l.9,0c.35,0,.64,0,.87-.09V12.24Z"/><path class="cls-5" d="M103.84,15.54a1.48,1.48,0,0,1-.83-1.08,13.91,13.91,0,0,1-.17-2.69,14,14,0,0,1,.17-2.7A1.48,1.48,0,0,1,103.84,8a6,6,0,0,1,2.21-.29,5.94,5.94,0,0,1,2.2.29,1.46,1.46,0,0,1,.83,1.08,13.75,13.75,0,0,1,.18,2.7,13.7,13.7,0,0,1-.18,2.69,1.46,1.46,0,0,1-.83,1.08,5.94,5.94,0,0,1-2.2.29A6,6,0,0,1,103.84,15.54Zm3.93-.57a1,1,0,0,0,.61-.81,13.62,13.62,0,0,0,.14-2.39,13.68,13.68,0,0,0-.14-2.4,1,1,0,0,0-.61-.81,8.84,8.84,0,0,0-3.45,0,1,1,0,0,0-.6.81,12.47,12.47,0,0,0-.15,2.4,12.42,12.42,0,0,0,.15,2.39,1,1,0,0,0,.6.81,8.84,8.84,0,0,0,3.45,0Z"/><path class="cls-5" d="M112.94,15.79c-.5,0-.94-.06-1.31-.11V15l1.33.1c.48,0,.88.05,1.2.05a8.75,8.75,0,0,0,1-.05,1.78,1.78,0,0,0,.65-.22.68.68,0,0,0,.35-.47,3.13,3.13,0,0,0,.09-.83,4.54,4.54,0,0,0-.06-.9.57.57,0,0,0-.31-.37,3.72,3.72,0,0,0-.88-.18l-2-.22a2.08,2.08,0,0,1-1.06-.32,1.18,1.18,0,0,1-.44-.64,5,5,0,0,1-.09-1.07,2.57,2.57,0,0,1,.3-1.38,1.56,1.56,0,0,1,.9-.63,6.12,6.12,0,0,1,1.59-.16c.45,0,.9,0,1.35,0s.81.08,1.07.13v.66c-.31,0-.68-.07-1.11-.1s-.83,0-1.19,0a6.52,6.52,0,0,0-1.1.07,1.88,1.88,0,0,0-.66.22.73.73,0,0,0-.33.44,2.52,2.52,0,0,0-.08.75,2.94,2.94,0,0,0,.07.77.61.61,0,0,0,.29.36,2.05,2.05,0,0,0,.69.16l2,.21a4.86,4.86,0,0,1,1.17.24,1,1,0,0,1,.55.63,4.24,4.24,0,0,1,.13,1.27,3,3,0,0,1-.31,1.54,1.36,1.36,0,0,1-.85.64,5.78,5.78,0,0,1-1.47.14C113.93,15.83,113.45,15.82,112.94,15.79Z"/><path class="cls-5" d="M11.36,13.89a7.43,7.43,0,0,1,2.52.4c.82.58,2,.89,2.5.3s0-1.61-.79-2.38a7.64,7.64,0,0,1-.93-2.35c.11-1-.23-2.23-1-2.35s-1.47,1-1.65,1.88a7.38,7.38,0,0,1-1.61,2c-.9.42-1.77,1.3-1.49,2S10.48,14.16,11.36,13.89Z"/><path class="cls-5" d="M14.75,3.42C16,3.47,16.49,6,16.29,7.91a26.16,26.16,0,0,0,1.64,4.69,1.88,1.88,0,0,0,.79.79,10.55,10.55,0,0,1-.84-5c.79-2.19.44-5.15-.75-5.84a2.71,2.71,0,0,0-3.68,1.2A1.8,1.8,0,0,1,14.75,3.42Z"/><path class="cls-5" d="M5,14C4.4,13,6.3,11.26,8.09,10.45,8.66,10.2,11,7.2,11.33,6.7a2,2,0,0,0,.29-1.09A10.62,10.62,0,0,1,7.68,8.86C5.38,9.27,3,11.05,3,12.42A2.71,2.71,0,0,0,5.87,15,1.88,1.88,0,0,1,5,14Z"/><path class="cls-5" d="M19.12,17.42c-.66,1-3.07.23-4.67-.92a25.88,25.88,0,0,0-4.87-.92,1.79,1.79,0,0,0-1.08.29,10.37,10.37,0,0,1,4.Line truncated

After

Width:  |  Height:  |  Size: 5.0 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 98 140"><defs><style>.cls-1,.cls-3{fill:none;}.cls-2{clip-path:url(#clip-path);}.cls-3{stroke:#2a96ff;stroke-miterlimit:10;stroke-width:0.5px;}.cls-4{fill:#4d4d4d;}.cls-5{fill:#e3493c;}</style><clipPath id="clip-path"><rect class="cls-1" x="144.54" y="59.59" width="600" height="600"/></clipPath></defs><title>aa-logo-vert</title><g id="Layer_1" data-name="Layer 1"><g class="cls-2"><circle class="cls-3" cx="210.14" cy="243.28" r="277.97"/></g></g><g id="Layer_4" data-name="Layer 4"><path class="cls-4" d="M11.27,108.29l-.38-3H8.62l-.38,3h-3L7.49,93.1h4.57l2.28,15.19ZM9.83,96.08H9.68L8.9,102.6h1.71Z"/><path class="cls-4" d="M18,93.1h3.69a4.53,4.53,0,0,1,2.79.67,3.22,3.22,0,0,1,1,2.11,41.13,41.13,0,0,1,.19,4.82,41,41,0,0,1-.19,4.81,3.19,3.19,0,0,1-1,2.11,4.46,4.46,0,0,1-2.79.67H18Zm3.69,12.43a.89.89,0,0,0,.71-.22,2.31,2.31,0,0,0,.25-1.15c0-.61,0-1.77,0-3.46s0-2.85,0-3.47a2.31,2.31,0,0,0-.25-1.15.89.89,0,0,0-.71-.22H21v9.67Z"/><path class="cls-4" d="M31.16,108.29,29.11,93.1h3l1.25,12.06h.23L34.8,93.1h3l-2.05,15.19Z"/><path class="cls-4" d="M46.35,108.29l-.38-3H43.7l-.38,3h-3L42.57,93.1h4.57l2.28,15.19ZM44.91,96.08h-.15L44,102.6h1.7Z"/><path class="cls-4" d="M58.44,108.29l-2.36-7.62H56v7.62H53.12V93.1h2.8L58.09,100h.11V93.1h2.89v15.19Z"/><path class="cls-4" d="M70.19,108.36a6.43,6.43,0,0,1-1.12.11,4,4,0,0,1-2.61-.71,3.72,3.72,0,0,1-1.1-2.28,31.28,31.28,0,0,1-.26-4.78,29.46,29.46,0,0,1,.28-4.77,3.82,3.82,0,0,1,1.12-2.3,3.9,3.9,0,0,1,2.57-.71,7.72,7.72,0,0,1,1.18.1,3.21,3.21,0,0,1,.85.24v2.53a11.75,11.75,0,0,0-1.48-.11,1.48,1.48,0,0,0-1.05.29,2.16,2.16,0,0,0-.35,1.23c0,.62-.08,1.79-.08,3.5s0,2.87.08,3.5a2.15,2.15,0,0,0,.35,1.22,1.48,1.48,0,0,0,1.05.29,9.89,9.89,0,0,0,1.53-.11v2.47A4.23,4.23,0,0,1,70.19,108.36Z"/><path class="cls-4" d="M75,108.29V93.1h6.09v2.76H78v3.38h2.7V102H78v3.53h3.07v2.76Z"/><path class="cls-4" d="M85.08,93.1h3.69a4.55,4.55,0,0,1,2.79.67,3.16,3.16,0,0,1,1,2.11,38.45,38.45,0,0,1,.2,4.82,38.37,38.37,0,0,1-.2,4.81,3.14,3.14,0,0,1-1,2.11,4.48,4.48,0,0,1-2.79.67H85.08Zm3.69,12.43a.89.89,0,0,0,.71-.22,2.31,2.31,0,0,0,.25-1.15c0-.61,0-1.77,0-3.46s0-2.85,0-3.47a2.31,2.31,0,0,0-.25-1.15.89.89,0,0,0-.71-.22h-.69v9.67Z"/><path class="cls-5" d="M19.79,134.79l-2.1-5.3H9.08L7,134.79H5.24l7.15-18.23h2l7.16,18.23Zm-6.33-16.24h-.14L9.64,127.9h7.5Z"/><path class="cls-5" d="M26.41,134.79V116.56h1.7v16.58H37v1.65Z"/><path class="cls-5" d="M48.1,126.76V125.2h6.2v9.3c-.87.14-1.84.26-2.9.35s-2,.15-2.8.15a12.88,12.88,0,0,1-4.9-.69,3.89,3.89,0,0,1-2.15-2.6,22.5,22.5,0,0,1-.58-6,22.11,22.11,0,0,1,.6-6A3.87,3.87,0,0,1,43.72,117a13.15,13.15,0,0,1,4.88-.67c.88,0,1.85.05,2.92.14s2,.22,2.7.36v1.51a33.49,33.49,0,0,0-4.66-.42,18.69,18.69,0,0,0-4.55.37,2.7,2.7,0,0,0-1.81,1.93,18.81,18.81,0,0,0-.53,5.43,23.5,23.5,0,0,0,.39,5.13,3,3,0,0,0,1.59,2.09,10.15,10.15,0,0,0,4,.55c.56,0,1.25,0,2.07-.08s1.47-.12,2-.19v-6.41Z"/><path class="cls-5" d="M61.91,134.32A3.33,3.33,0,0,1,60,131.86a31.94,31.94,0,0,1-.41-6.19,31.89,31.89,0,0,1,.41-6.18A3.33,3.33,0,0,1,61.91,117a13.45,13.45,0,0,1,5.07-.67A13.42,13.42,0,0,1,72,117a3.33,3.33,0,0,1,1.89,2.47,31.89,31.89,0,0,1,.41,6.18,31.94,31.94,0,0,1-.41,6.19A3.33,3.33,0,0,1,72,134.32,13.38,13.38,0,0,1,67,135,13.4,13.4,0,0,1,61.91,134.32Zm9-1.29a2.34,2.34,0,0,0,1.37-1.86,29.55,29.55,0,0,0,.34-5.5,29.7,29.7,0,0,0-.34-5.5,2.32,2.32,0,0,0-1.37-1.85,13.69,13.69,0,0,0-4-.38,13.73,13.73,0,0,0-4,.38,2.32,2.32,0,0,0-1.37,1.85,28.82,28.82,0,0,0-.34,5.5,28.68,28.68,0,0,0,.34,5.5A2.34,2.34,0,0,0,63,133a13.73,13.73,0,0,0,4,.38A13.69,13.69,0,0,0,70.94,133Z"/><path class="cls-5" d="M82.89,134.91c-1.17-.07-2.18-.15-3-.25v-1.59c.91.08,1.93.16,3,.23s2,.11,2.76.11a17.72,17.72,0,0,0,2.32-.12,4,4,0,0,0,1.49-.49,1.67,1.67,0,0,0,.81-1.07,7.68,7.68,0,0,0,.2-1.92,9.6,9.6,0,0,0-.15-2.07,1.14,1.14,0,0,0-.71-.83,7.63,7.63,0,0,0-2-.42L83,126a4.91,4.91,0,0,1-2.42-.74,2.61,2.61,0,0,1-1-1.47,10.4,10.4,0,0,1-.23-2.45,5.81,5.81,0,0,1,.71-3.17,3.47,3.47,0,0,1,2-1.44,14.24,14.24,0,0,1,3.66-.37c1,0,2,0,3.09.1a19.49,19.49,0,0,1,2.44.29v1.51c-.7-.08-1.55-.16-2.54-.22s-1.9-.09-2.73-.09a15.54,15.54,0,0,0-2.52.16,4.18,4.18,0,0,0-1.51.5,1.74,1.74,0,0,0-.76,1,6,6,0,0,0-.19,1.72,6.83,6.83,0,0,0,.17,1.76,1.32,1.32,0,0,0,.67.82,4.9,4.9,0,0,0,1.57.39l4.51.47a10.3,10.3,0,0,1,2.69.56,2.23,2.23,0,0,1,1.25,1.43,9.9,9.9,0,0,1,.3,2.91,6.84,6.84,0,0,1-.72,3.54,3.17,3.17,0,0,1-2,1.47,14.17,14.17,0,0,1-3.38.32C85.14,135,84.05,135,82.89,134.91Z"/><path class="cls-5" d="M47.08,49.62c1.17-.36,8.61.83,9.61,1.53,3.13,2.21,7.71,3.41,9.55,1.15s-.08-6.13-3-9.1c-.88-.88-3.7-7.75-3.56-9,.42-3.87-.85-8.5-3.73-9s-5.61,3.66-6.3,7.16c-.24,1.22-5,7.11-6.14,7.62-3.48,1.62-6.77,5-5.73,7.69S43.7,50.65,47.08,49.62Z"/><path class="cls-5" d="M60,9.61c4.68.2,6.65,9.72,5.89,17.18-.24,2.37,5.27,15.71,6.24,17.91a7.29,7.29,0,0,0,3,3C71.63,38.07,71.32,30.32,72,28.51c3-8.4,1.71-19.69-2.85-22.32-3.07-1.77-9.79-2.48-14.07,4.56A6.91,6.91,0,0,1,60,9.61Z"/><path class="cls-5" d="M22.61,50.2C20.Line truncated

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/mstile-150x150.png"/>
<TileColor>#da532c</TileColor>
</tile>
</msapplication>
</browserconfig>
Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 758 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@@ -0,0 +1,9 @@
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#e3493c">
<meta name="apple-mobile-web-app-title" content="Advanced Algos">
<meta name="application-name" content="Advanced Algos">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

@@ -0,0 +1 @@
<svg version="1" xmlns="http://www.w3.org/2000/svg" width="1365.333" height="1365.333" viewBox="0 0 1024.000000 1024.000000"><path d="M685.9 27.4c-.2.2-3 .7-6.1 1-12.6 1.5-34.6 8.5-45.2 14.5-2 1.2-5.3 3.1-7.3 4.2-14.3 8.1-30.2 22.3-43.5 38.8-5.9 7.4-16.2 22.1-15.5 22.1.2 0 3.6-1.7 7.5-3.9 17.4-9.6 28.8-12.1 52.2-11.7 13.4.3 17.7.8 23.1 2.5 25.1 8 45.2 36.6 58.9 83.7 1.8 6 3.3 11.6 3.5 12.4 2.3 10.8 3.5 17.1 4 20 .3 1.9 1 6 1.5 9 1.2 7.3 1.8 11.3 2.5 18.5.4 3.3.8 7.6 1.1 9.5 1.6 14.3 2.2 51.4 1 69.5-1.4 21.3-1.5 26-.5 31 .5 2.7 1.2 6.3 1.5 8 2.3 12.9 20.6 69 33.4 102.5 1.6 4.1 4.8 12.4 7.1 18.5 17.1 45.2 47.3 118.6 49.1 119.3.4.2.8.9.8 1.5.1 3.8 18.3 22 29.2 29.1 4.7 3.1 8.8 5.6 9 5.6.3 0-3.2-10.9-7.7-24.3-4.5-13.3-8.4-25.3-8.7-26.7-.4-1.4-2-7.2-3.7-13-4.3-14.5-12.2-45.3-13.7-54-.3-1.4-.7-3.3-1-4.2-.3-1-.7-3-1-4.5-.2-1.6-.9-4.8-1.4-7.3-.5-2.5-1.4-7.2-2-10.5-.5-3.3-1.2-7.1-1.5-8.5-.3-1.4-1-5.7-1.5-9.5-.6-3.9-1.2-8.1-1.5-9.5-.3-2.3-.7-5.4-2-16.3-3.1-25.8-3.8-58.6-1.5-73.2.7-4.4 2.2-10.7 3.5-14 2.3-6.1 9-28.9 9.9-33.5.3-1.4 1.2-5.2 2-8.5s1.7-7.4 1.9-9c.3-1.7 1.4-8.2 2.6-14.6 1.1-6.3 2.3-14.7 2.6-18.5.4-3.8.9-8.3 1.1-9.9 2.2-16.2 2.2-69.4 0-83.5-.2-1.4-.7-5-1.1-8-6.7-56.6-26.4-102.4-53.1-123.1-11.1-8.5-31-16.4-49.9-19.7-9.6-1.7-38.4-2.9-39.6-1.8zM465 215.4c-2.3 3-9.7 11.7-14.5 17-1.1 1.2-5.6 6.2-10 11.1-8.3 9.3-43.9 45.2-53.5 54-51.1 46.9-108.8 86-132.5 90-2.2.4-4.4.8-5 .9-.5.2-2.8.6-5 1.1-24.5 4.7-70 20.4-91 31.3-2.7 1.4-5.2 2.6-5.5 2.7-.7.1-12.3 6.2-16.7 8.7-2.1 1.2-5.4 3.1-7.5 4.2C62.4 471.4 16.3 519 4.3 559.8.9 571.3.5 590 3.4 603.5c2.6 12.1 7.2 25.6 11.8 35 19.6 39.1 52.7 65.8 95.3 76.8 5.5 1.4 12 2.9 14.5 3.2 2.5.4 5.4.9 6.5 1.1 2.8.5 11.7 1.4 19.5 1.9l6.4.4-3.4-2.1c-20.8-12.5-29.7-21.3-39-38.3-1.8-3.3-4.3-7.8-5.5-10-6.1-11.2-8.2-22.8-6.4-35.1 7.4-48 72.3-111.2 159.4-155 10.5-5.3 21-11.2 23.5-13.1 8.7-6.7 26.9-25.3 45.4-46.3 1.7-2 4.9-5.6 7.1-8.1 2.2-2.4 6-6.9 8.5-9.8 2.5-3 5-5.9 5.5-6.5.6-.6 3-3.6 5.5-6.6 6.5-8 7.1-8.6 15.2-18.5 12.7-15.4 51.5-64.5 61.3-77.6 1.1-1.5 5.9-7.8 10.6-14 11.5-15.2 13.3-18.1 16.8-26.9 3-7.7 3.5-9.3 5.1-19 1.2-7.1 1.9-21.9 1.1-22.4-.3-.2-1.7 1.1-3.1 2.8zM563.9 315c-21.5 5.4-43.9 28.6-59.4 61.3-5.2 11-10.1 24.9-12.5 35.7-2 8.8-6.1 16.2-21 37.4-1.8 2.6-17.8 23.2-20.7 26.6-14.7 17.6-22.4 26.2-31.2 35.1-8.7 8.6-12.2 11.3-19.6 15.2-16.7 8.7-25.6 14.5-37 23.8-22.2 18.1-36.8 38.2-41 56.4-1.6 6.6-2.2 17.6-1.1 19.3.3.5.7 2.1 1 3.7.8 4.3 5.3 12.7 9.1 16.8 10.1 11.1 27.7 18.5 50.5 21.3 12.2 1.5 36.1.8 49-1.6 11.6-2 12.6-2.3 20.5-4.5s31.7-2.2 43.5 0c.8.2 4.4.6 8 1 3.6.4 7.4.9 8.4 1.1 1.1.2 4.2.6 6.9.9 2.8.3 5.3.8 5.6.9.3.2 2.9.7 5.6 1 9.1 1.3 39 7.5 47.9 10.1 8.9 2.6 18.5 7 20.6 9.6 1.9 2.3 30.1 16.5 39.5 20 9.1 3.3 26.6 7.7 33.7 8.6 9.2 1.1 23.9.7 30-.7 19.5-4.6 33.3-18.5 36.3-36.7.7-4.2.8-19 .1-20.1-.2-.4-.7-2.4-1-4.6-1-6.1-5.5-18.3-10.3-28.1-4.2-8.3-15.4-26.1-20.1-31.6-5.8-7-14.5-17-18.6-21.4-2.6-2.8-6.5-8-8.7-11.7-6.3-10.8-17.6-35.1-25.4-55.3-1.5-3.9-3.3-8.4-4-10-1.4-3.5-4.9-12.8-5-13.5 0-.3-1.2-3.7-2.5-7.5-1.3-3.9-2.5-7.5-2.6-8-.1-.6-.9-3.5-1.8-6.6-2.6-8.9-2.8-10-2.6-17.4.7-25.5.3-39.3-1.3-49.5-.3-1.4-.8-4.5-1.2-7-.3-2.4-.8-4.7-1-5.1-.2-.3-.7-2.1-1-4-.9-5.4-6.3-20.6-9.7-27.3-7.5-14.9-16.6-24.9-27.5-30.3-6.3-3.1-8.3-3.6-16-3.9-4.8-.2-10.4.1-12.4.6zM340 752.1c-12.3 2.1-18.9 4.4-31.5 10.7-10.5 5.3-11.8 4.4 13 9.2 69 13.5 135.5 34.9 186.8 60.2 24.5 12.1 41 22.8 49.7 32.3 24.3 26.6 37.9 39.4 60 56.6 50.3 39.2 116.2 69.8 162.5 75.5 2.8.3 6.8.9 9 1.3 4.8.9 28.3.6 34-.3 23.2-4 37.1-11.8 56.6-31.7 33-33.8 46.8-81.2 37.4-128.4-3.2-16-8-29.9-16.2-46.5l-4.2-8.5-.1 8c-.1 4.4-.3 8.7-.4 9.5-.2.8-.6 3.8-1 6.6-1.8 14.4-15.1 40.8-26.4 52.7-17.8 18.7-53.6 23.1-99.2 12.2-5.8-1.4-11.5-2.7-12.6-3-1.2-.3-7.7-2.3-14.5-4.6-36.3-12-78-32.8-111.4-55.7-6-4.1-13-8.4-15.5-9.4-2.5-1.1-5.4-2.3-6.5-2.8-5.6-2.4-39.7-11.2-52.5-13.5-1.9-.3-4.2-.7-5-.9-.8-.1-4-.8-7-1.4-9.8-2-26.4-5.1-30-5.6-3-.5-29.1-4.8-37-6.1-1.4-.2-4.3-.7-6.5-1-6.9-1.1-9.8-1.5-15.5-2.5-3-.5-8.2-1.2-11.5-1.6-3.3-.3-6.2-.7-6.5-.9-.3-.2-4.4-.9-9-1.5-4.7-.6-9.6-1.3-11-1.5-1.4-.2-6.3-.9-11-1.5s-9.6-1.3-11-1.5c-5.9-.8-10.8-1.5-15-2-5.1-.6-9.4-1.2-16-2.1-7.1-.9-20.1-1.1-25-.3z"/></svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

@@ -0,0 +1,19 @@
{
"name": "Advanced Algos",
"short_name": "Advanced Algos",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}
+258
View File
@@ -0,0 +1,258 @@
import React, { Component } from 'react'
import {graphql, compose} from 'react-apollo'
import {getDescendentsQuery} from '../queries/queries'
// Materia UI
import { withStyles } from '@material-ui/core/styles'
import Card from '@material-ui/core/Card'
import CardActionArea from '@material-ui/core/CardActionArea'
import CardActions from '@material-ui/core/CardActions'
import CardContent from '@material-ui/core/CardContent'
import CardMedia from '@material-ui/core/CardMedia'
import Typography from '@material-ui/core/Typography'
import Grid from '@material-ui/core/Grid'
// Material UI Nestled Lists
import ListSubheader from '@material-ui/core/ListSubheader';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import Collapse from '@material-ui/core/Collapse';
import ExpandLess from '@material-ui/icons/ExpandLess';
import ExpandMore from '@material-ui/icons/ExpandMore';
import StarBorder from '@material-ui/icons/StarBorder';
// Images
import PortraitImage from '../img/portrait.jpg'
const styles = theme => ({
card: {
maxWidth: 300,
minWidth: 300,
paddingTop: '30'
},
media: {
height: 0,
paddingTop: '56.25%', // 16:9,
marginTop: '30',
minWidth: 300
},
typography: {
maxWidth: 345,
minWidth: 300,
paddingTop: '30'
},
appBar: {
position: 'relative'
},
flex: {
flex: 1
},
grid: {
paddingTop: '30',
marginTop: 30
},
list: {
width: '80%',
marginLeft: '10%',
marginTop: 25
},
button: {
margin: theme.spacing.unit,
marginTop: theme.spacing.unit * 3
},
nested: {
paddingLeft: theme.spacing.unit * 4,
},
})
class DescendentsTree extends Component {
constructor (props) {
super(props)
this.state = {
id: '',
open: true
}
}
handleClick = () => {
this.setState(state => ({ open: !state.open }));
};
displayIcons(amount) {
switch (amount) {
case 1: return (
<div>
<ListItemIcon>
<StarBorder />
</ListItemIcon>
</div>
)
case 2: return (
<div>
<ListItemIcon>
<StarBorder />
</ListItemIcon>
<ListItemIcon>
<StarBorder />
</ListItemIcon>
</div>
)
case 3: return (
<div>
<ListItemIcon>
<StarBorder />
</ListItemIcon>
<ListItemIcon>
<StarBorder />
</ListItemIcon>
<ListItemIcon>
<StarBorder />
</ListItemIcon>
</div>
)
default: return(<div/>)
}
}
displayNestedListItems(node, level) {
const { classes } = this.props
return node.descendents.map(descendent => {
return (
<div key={descendent.alias}>
<ListItem button className={classes.nested}>
{this.displayIcons(level)}
<Card className={classes.card}>
<CardActionArea>
<CardMedia
className={classes.media}
image={PortraitImage}
title='User Profile'
/>
<CardContent>
<Typography gutterBottom variant='headline' component='h2'>
{descendent.alias}
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Grid container justify='center' spacing={8}>
<Grid item />
</Grid>
</CardActions>
</Card>
</ListItem>
{this.displayNestedList(descendent, level)}
</div>
)
}
)
}
displayNestedList(descendent, level) {
const primaryText = "Children of " + descendent.alias
if (descendent.descendents !== undefined) {
if (descendent.descendents.length > 0) {
return(
<List component="div" disablePadding>
<ListItem button onClick={ () => {
this.setState(state => ({ [descendent.alias]: !state[descendent.alias] }));
}
}>
<ListItemText inset primary={primaryText} />
{this.state[descendent.alias] ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={this.state[descendent.alias]} timeout="auto" unmountOnExit>
{this.displayNestedListItems(descendent, level + 1)}
</Collapse>
</List>
)
} else {
return (<div/>)
}
}
}
displayTopList () {
let data = this.props.data
const { classes } = this.props
if (data.loading) {
return (<div> Loading Descendents... </div>)
} else {
if (data.descendents === undefined) {
return (<div> No Descendents to Display </div>)
} else {
return data.descendents.map(descendent => {
return (
<div key={descendent.alias}>
<ListItem button>
{this.displayIcons(1)}
<Card className={classes.card}>
<CardActionArea>
<CardMedia
className={classes.media}
image={PortraitImage}
title='User Profile'
/>
<CardContent>
<Typography gutterBottom variant='headline' component='h2'>
{descendent.alias}
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Grid container justify='center' spacing={8}>
<Grid item />
</Grid>
</CardActions>
</Card>
</ListItem>
{this.displayNestedList(descendent, 1)}
</div>
)
})
}
}
}
render () {
const { classes } = this.props
return (
<div>
<List
component="nav"
subheader={<ListSubheader component="div"></ListSubheader>}
className={classes.list}
>
{this.displayTopList()}
</List>
</div>
)
}
}
export default compose(
graphql(getDescendentsQuery, { // What follows is the way to pass a parameter to a query.
options: (props) => {
return {
variables: {
name: 'getDescendentsQuery',
id: props.userId
}
}
}}),
withStyles(styles)
)(DescendentsTree) // This technique binds more than one query to a single component.
-84
View File
@@ -1,84 +0,0 @@
import React, { Component } from 'react'
import { NavLink } from 'react-router-dom'
import { compose } from 'recompose'
import { withStyles } from '@material-ui/core/styles'
import Button from '@material-ui/core/Button'
import Grid from '@material-ui/core/Grid'
// Images
import AALogo from '../img/aa-logo.png'
const styles = theme => ({
root: {
flexGrow: 1,
padding: 100
},
img: {
margin: 'auto',
display: 'block',
maxWidth: 120,
maxHeight: 24
},
button: {
margin: theme.spacing.unit
}
})
class Footer extends Component {
constructor (props) {
super(props)
this.state = {
selected: '',
user: null
}
}
render () {
const { classes } = this.props
return (
<Grid className={classes.button} container justify='center' spacing={24}>
<Grid item>
<Button color='primary' className={classes.button}>
<NavLink color='inherit' exact to='/'>Home</NavLink>
</Button>
</Grid>
<Grid item>
<Button color='primary' className={classes.button}>
<NavLink to='/browse'>Browse</NavLink>
</Button>
</Grid>
<Grid item>
<Button color='primary' className={classes.button}>
<NavLink to='/search'>Search</NavLink>
</Button>
</Grid>
<Grid item>
<Button color='primary' className={classes.button}>
<a href='http://www.advancedalgos.net'><img className={classes.img} alt='complex' src={AALogo} /></a>
</Button>
</Grid>
<Grid item>
<Button color='primary' className={classes.button}>
<NavLink color='inherit' exact to='/contact'>Contact</NavLink>
</Button>
</Grid>
<Grid item>
<Button color='primary' className={classes.button}>
<NavLink to='/about'>About</NavLink>
</Button>
</Grid>
<Grid item>
<Button color='primary' className={classes.button}>
<NavLink to='/modules'>Modules</NavLink>
</Button>
</Grid>
</Grid>
)
}
}
export default compose(
withStyles(styles)
)(Footer)
+69 -27
View File
@@ -2,9 +2,9 @@ import React, { Component } from 'react'
import { compose } from 'recompose'
import { withStyles } from '@material-ui/core/styles'
import {LineChart} from 'react-easy-chart'
import Paper from '@material-ui/core/Paper'
import Grid from '@material-ui/core/Grid'
import Typography from '@material-ui/core/Typography'
import CssBaseline from '@material-ui/core/CssBaseline'
const styles = theme => ({
root: {
@@ -19,6 +19,26 @@ const styles = theme => ({
width: '100%',
marginTop: 20,
marginBottom: 20
},
'@global': {
body: {
backgroundColor: theme.palette.common.white
}
},
layout: {
width: 'auto',
marginLeft: theme.spacing.unit * 3,
marginRight: theme.spacing.unit * 3,
[theme.breakpoints.up(900 + theme.spacing.unit * 3 * 2)]: {
width: 900,
marginLeft: 'auto',
marginRight: 'auto'
}
},
heroContent: {
maxWidth: 600,
margin: '0 auto',
padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px`
}
})
@@ -27,41 +47,63 @@ class Home extends Component {
render () {
const { classes } = this.props
return (
<Paper className={classes.root}>
<React.Fragment>
<CssBaseline />
<main className={classes.layout}>
<div className={classes.heroContent}>
<Typography
variant='display3'
align='center'
color='textPrimary'
gutterBottom
>
Collaborate. Innovate. Evolve.
</Typography>
<Typography
variant='title'
align='center'
color='textSecondary'
component='h3'
>
Welcome to Advanced Algos Users Module
</Typography>
</div>
</main>
<Grid container justify='center' spacing={24}>
<Grid className={classes.grid} item>
<Typography className={classes.typography} gutterBottom variant='headline' component='h2'>
Welcome to the Users Module
</Typography>
Intro
</Typography>
<Typography className={classes.typography} component='p'>
This module is responsible for managing users across the Advanced Algos system. Here you can browse the Users Directory, search for users and get to their profiles. You can create your own User profile if you sign up, or manage it if you already have one by logging in.
</Typography>
This module is responsible for managing users across the Advanced Algos system. Here you can browse the Users Directory, search for users and get to their profiles. You can create your own User profile if you sign up, or manage it if you already have one by logging in.
</Typography>
<Typography className={classes.typography} gutterBottom variant='headline' component='h2'>
Development Status
</Typography>
Development Status
</Typography>
<Typography className={classes.typography} component='p'>
This module is is currently under heavy development. Implementation started 1st of September 2018 and this is the result of the 1st sprint of 2 weeks of work.
</Typography>
This module is is currently under heavy development. Implementation started 1st of September 2018 and this is the result of the 1st sprint of 2 weeks of work.
</Typography>
<Typography className={classes.typography} gutterBottom variant='headline' component='h2'>
What can you do?
</Typography>
What can you do?
</Typography>
<Typography className={classes.typography} component='p'>
Currently you can use the Browse section to list all registered users. Clicking on View Profile you can see some more info about that user. You can signup with your Github account and manage your profile information while logged in. You will find all features under develpment with a dialog indicating it is not ready.
</Typography>
Currently you can use the Browse section to list all registered users. Clicking on View Profile you can see some more info about that user. You can signup with your Github account and manage your profile information while logged in. You will find all features under develpment with a dialog indicating it is not ready.
</Typography>
<Typography className={classes.typography} gutterBottom variant='headline' component='h2'>
What is next?
</Typography>
What is next?
</Typography>
<Typography className={classes.typography} component='p'>
The major features for the next sprint are:
</Typography>
The major features for the next sprint are:
</Typography>
<ul>
<li>1. Managing profile images.</li>
<li>2. Making sure that Auth0 integration server side is working well.</li>
<li>3. Making sure that mutations can not be impersonated.</li>
</ul>
<Typography className={classes.typography} component='p' >
Below, you can see some usage statistics of this module, in this case, the total amount of users over time. [data is not real yet.]
</Typography>
Below, you can see some usage statistics of this module, in this case, the total amount of users over time. [data is not real yet.]
</Typography>
<LineChart
xType={'time'}
axes
@@ -70,18 +112,18 @@ class Home extends Component {
height={250}
data={[
[
{ x: '1-Sep-17', y: 2 },
{ x: '2-Sep-17', y: 4 },
{ x: '3-Sep-17', y: 5 },
{ x: '4-Sep-17', y: 6 },
{ x: '5-Sep-17', y: 7 }
{ x: '1-Sep-17', y: 2 },
{ x: '2-Sep-17', y: 4 },
{ x: '3-Sep-17', y: 5 },
{ x: '4-Sep-17', y: 6 },
{ x: '5-Sep-17', y: 7 }
]
]}
/>
/>
</Grid>
</Grid>
</Paper>
</React.Fragment>
)
}
+3 -3
View File
@@ -20,7 +20,7 @@ import { Link } from 'react-router-dom'
import LoggedInUser from './LoggedInUser'
// Images
import AALogo from '../img/aa-logo-dark-8.png'
import AALogo from '../assets/logos/advanced-algos/aa-logo-dark.svg'
const ModulesLink = props => <Link to='/modules' {...props} />
const AboutLink = props => <Link to='/about' {...props} />
@@ -43,8 +43,8 @@ const styles = {
img: {
margin: 20,
display: 'block',
maxWidth: 120,
maxHeight: 24
maxWidth: 240,
maxHeight: 48
}
}
+322
View File
@@ -0,0 +1,322 @@
import React from 'react';
import {graphql, compose} from 'react-apollo'
import {updateUserImagesMutation, getUsersQuery} from '../queries/queries'
import Avatar from '@material-ui/core/Avatar';
import classNames from 'classnames';
import ReactFilestack from 'filestack-react'
// Material-ui
import { withStyles } from '@material-ui/core/styles'
import Button from '@material-ui/core/Button';
import Paper from '@material-ui/core/Paper'
import Grid from '@material-ui/core/Grid'
import Typography from '@material-ui/core/Typography'
const options = {
accept: ['image/jpeg', 'image/jpg', 'image/png'],
maxFiles: 1,
imageDim: [300, 300],
maxSize: 0.25 * 1024 * 1024, // 1/4 of 1 Mb
storeTo: {
location: 's3',
},
};
const styles = theme => ({
button: {
margin: theme.spacing.unit,
marginTop: theme.spacing.unit * 3
},
row: {
display: 'flex',
justifyContent: 'center',
},
avatar: {
margin: 10,
},
bigAvatar: {
width: 60,
height: 60,
},
root: {
width: '50%',
flexGrow: 1,
padding: 10,
marginLeft: '25%',
marginTop: '2%'
},
typography: {
width: '80%',
marginLeft: '10%',
marginTop: 40
}
})
class ProfileImages extends React.Component {
constructor (props) {
super(props)
this.defaultValuesSet = false
this.state = {
avatarHandle: '',
avatarChangeDate: '',
newAvatarHandle: '',
saveDisabled: true,
uploadToolDisabled: false,
showNewAvatar: false,
needToWait: false,
removeCurrentAvatar: false
}
}
submitForm (e) {
e.preventDefault()
this.props.updateUserImagesMutation({
variables: {
id: this.state.id,
avatarHandle: this.state.newAvatarHandle,
avatarChangeDate: this.state.avatarChangeDate
},
refetchQueries: [{ query: getUsersQuery}] // This allow us to re run whatever queries are necesary after the mutation.
})
this.setState({saveDisabled: true, removeCurrentAvatar:true})
/* Before we are done, we need to update the state of the local storage. */
let user = JSON.parse(localStorage.getItem('loggedInUser'))
user.avatarHandle = this.state.newAvatarHandle
user.avatarChangeDate = this.state.avatarChangeDate
localStorage.setItem('loggedInUser', JSON.stringify(user))
}
componentWillMount () {
if (this.defaultValuesSet === false) {
let userData = localStorage.getItem('loggedInUser')
if (userData === 'undefined') { return }
let user = JSON.parse(userData)
this.defaultValuesSet = true
/* To avoid console warning, we need to take care of the fields that are null. */
if (user.avatarHandle === null) { user.avatarHandle = '' }
if (user.avatarChangeDate === null) { user.avatarChangeDate = '' }
/* Here we will check that the user does not change the avatar more often than once a day. */
let avatarChangeDate = (new Date(user.avatarChangeDate)).valueOf()
let now = (new Date()).valueOf()
let timePassed = now - avatarChangeDate
let oneDay = 1000 * 60 * 60 * 24
if (timePassed < oneDay) {
this.setState({
needToWait: true
})
} else {
this.setState({
needToWait: false
})
}
/* Now we are ready to set the initial state. */
this.setState({
id: user.id,
avatarHandle: user.avatarHandle,
avatarChangeDate: user.avatarChangeDate
})
}
}
onSuccess = (uploadResults) => {
console.log('onSuccess')
console.log(uploadResults)
const handle = uploadResults.filesUploaded[0].handle
let localDate = new Date()
let currentDate = new Date(Date.UTC(
localDate.getUTCFullYear(),
localDate.getUTCMonth(),
localDate.getUTCDate(),
localDate.getUTCHours(),
localDate.getUTCMinutes(),
localDate.getUTCSeconds(),
localDate.getUTCMilliseconds())
)
currentDate.toISOString()
this.setState(
{
newAvatarHandle: handle,
avatarChangeDate: currentDate,
showNewAvatar: true,
uploadToolDisabled: true,
saveDisabled: false
}
)
}
onError = (err) => {
console.log('onError')
console.log(err)
}
onRemoveSuccess = (err) => {
console.log('onRemoveSuccess')
console.log(err)
}
showCurrentAvatar() {
const { classes } = this.props
if (this.state.removeCurrentAvatar === false) {
return (
<div>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
This is your current Avatar:
</Typography>
<Grid container justify='center' >
<Grid item>
<Avatar
alt="Avatar"
src={"https://cdn.filestackcontent.com/" + this.state.avatarHandle}
className={classNames(classes.bigAvatar)}
/>
</Grid>
</Grid>
</div>
)
} else {
return (
<div>
<ReactFilestack
apikey={'AH97QJOXTHwdBXjydQgABz'}
mode="remove"
options={options}
fileHandle={this.state.avatarHandle}
onSuccess={this.onRemoveSuccess}
onError={this.onError}
link
></ReactFilestack>
</div>
)
}
}
showNewAvatar() {
if (this.state.showNewAvatar === true) {
const { classes } = this.props
return (
<div>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
This is how your new avatar will look like. Press save to proceed with the change.
</Typography>
<Grid container justify='center' >
<Grid item>
<Avatar
alt="Avatar"
src={"https://cdn.filestackcontent.com/" + this.state.newAvatarHandle}
className={classNames(classes.bigAvatar)}
/>
</Grid>
</Grid>
</div>
)
}
}
showUploadTool() {
const { classes } = this.props
if (this.state.needToWait === true) {
return (
<div>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
You updated your Avatar in the last 24 hours. As a protection against denial of service attacks, the system does not allow users to update their Avatar in less than 24 hs since their last update. Please come back tomorrow.
</Typography>
</div>
)
} else {
return(
<div>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
If you want, you can choose a new one by picking an image from your computer, camera or the web, and crop it with the following tool.
</Typography>
<Grid container justify='center' >
<Grid item>
<Button
disabled={this.state.uploadToolDisabled}
variant='contained'
color='secondary'
className={classes.button}>
<ReactFilestack
apikey={'AH97QJOXTHwdBXjydQgABz'}
options={options}
onSuccess={this.onSuccess}
onError={this.onError}
link
>File Upload Tool</ReactFilestack>
</Button>
</Grid>
</Grid>
</div>
)
}
}
render() {
const { classes } = this.props
return (
<Paper className={classes.root}>
<Typography className={classes.typography} variant='headline' gutterBottom>
Profile Images
</Typography>
<form onSubmit={this.submitForm.bind(this)}>
{this.showCurrentAvatar()}
{this.showUploadTool()}
{this.showNewAvatar()}
<Grid container justify='center' >
<Grid item>
<Button
disabled={this.state.saveDisabled}
variant='contained'
color='secondary'
className={classes.button}
onClick={this.submitForm.bind(this)}
>Save</Button>
</Grid>
</Grid>
</form>
</Paper>
);
}
}
export default compose(
graphql(updateUserImagesMutation, {name: 'updateUserImagesMutation'}),
withStyles(styles)
)(ProfileImages) // This technique binds more than one query to a single component.
@@ -62,7 +62,7 @@ const styles = theme => ({
}
})
class UserUpdate extends Component {
class ProfileSheet extends Component {
constructor (props) {
super(props)
@@ -467,4 +467,4 @@ export default compose(
graphql(getRolesQuery, {name: 'getRolesQuery'}),
graphql(updateUserMutation, {name: 'updateUserMutation'}),
withStyles(styles)
)(UserUpdate) // This technique binds more than one query to a single component.
)(ProfileSheet) // This technique binds more than one query to a single component.
+29 -40
View File
@@ -1,48 +1,37 @@
import React from 'react';
import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
import React, { Component } from 'react'
import UserSearch from './UserSearch'
import {compose} from 'react-apollo'
class Search extends React.Component {
state = {
open: true,
};
// Materia UI
handleClickOpen = () => {
this.setState({ open: true });
};
import { withStyles } from '@material-ui/core/styles'
import Paper from '@material-ui/core/Paper'
handleClose = () => {
this.setState({ open: false });
};
const styles = theme => ({
root: {
flexGrow: 1,
padding: 60,
margin: 2
}
})
render() {
class Search extends Component {
constructor (props) {
super(props)
this.state = {
}
}
render () {
const { classes } = this.props
return (
<div>
<Dialog
open={this.state.open}
onClose={this.handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">{"Section under development."}</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
The functionality of this section has not been developed yet. We expect to have it for October 2018. Thanks for your understanding.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={this.handleClose} color="primary" autoFocus>
Close
</Button>
</DialogActions>
</Dialog>
</div>
);
<Paper className={classes.root}>
<UserSearch />
</Paper>
)
}
}
export default Search;
export default compose(
withStyles(styles)
)(Search)
-48
View File
@@ -1,48 +0,0 @@
import React from 'react';
import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
class UserImages extends React.Component {
state = {
open: true,
};
handleClickOpen = () => {
this.setState({ open: true });
};
handleClose = () => {
this.setState({ open: false });
};
render() {
return (
<div>
<Dialog
open={this.state.open}
onClose={this.handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">{"Section under development."}</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
The functionality of this section has not been developed yet. We expect to have it for October 2018. Thanks for your understanding.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={this.handleClose} color="primary" autoFocus>
Close
</Button>
</DialogActions>
</Dialog>
</div>
);
}
}
export default UserImages;
+2
View File
@@ -143,7 +143,9 @@ class UserList extends Component {
</Button>
</Toolbar>
</AppBar>
<Paper className={classes.root}>
<UserProfile userId={this.state.selected}/>
</Paper>
</Dialog>
</Grid>
<Grid item>
+5 -10
View File
@@ -6,7 +6,6 @@ import {getUserProfileQuery} from '../queries/queries'
import { withStyles } from '@material-ui/core/styles'
import Grid from '@material-ui/core/Grid'
import Paper from '@material-ui/core/Paper'
import Card from '@material-ui/core/Card'
import CardActionArea from '@material-ui/core/CardActionArea'
import CardContent from '@material-ui/core/CardContent'
@@ -24,15 +23,14 @@ const styles = theme => ({
margin: 2
},
card: {
maxWidth: 800,
minWidth: 800,
width: '80%',
paddingTop: '30'
},
media: {
height: 0,
paddingTop: '56.25%', // 16:9,
marginTop: '30',
minWidth: 800
minWidth: '80%'
},
grid: {
paddingTop: '30',
@@ -92,13 +90,10 @@ class UserProfile extends Component {
}
render () {
const { classes } = this.props
return (
<Paper className={classes.root}>
<Grid container justify='center' spacing={24}>
{this.displayUserProfile()}
</Grid>
</Paper>
<Grid container justify='center' spacing={24}>
{this.displayUserProfile()}
</Grid>
)
}
}
+267
View File
@@ -0,0 +1,267 @@
import React, { Component } from 'react'
import {graphql, compose} from 'react-apollo'
import {getUsersBySearchFields} from '../queries/queries'
// Materia UI
import { withStyles } from '@material-ui/core/styles'
import Card from '@material-ui/core/Card'
import CardActionArea from '@material-ui/core/CardActionArea'
import CardActions from '@material-ui/core/CardActions'
import CardContent from '@material-ui/core/CardContent'
import CardMedia from '@material-ui/core/CardMedia'
import Button from '@material-ui/core/Button'
import Typography from '@material-ui/core/Typography'
import Grid from '@material-ui/core/Grid'
import TextField from '@material-ui/core/TextField'
// Images
import PortraitImage from '../img/portrait.jpg'
const styles = theme => ({
card: {
maxWidth: 150,
minWidth: 150,
paddingTop: '30',
marginBottom: 40
},
media: {
height: 0,
paddingTop: '56.25%', // 16:9,
marginTop: '30',
minWidth: 300
},
typography: {
maxWidth: 345,
minWidth: 300,
paddingTop: '30'
},
appBar: {
position: 'relative'
},
flex: {
flex: 1
},
grid: {
paddingTop: '30',
marginTop: 30
},
inputField: {
width: '80%',
marginLeft: '10%',
marginTop: 25
},
formTypography: {
width: '80%',
marginLeft: '10%',
marginTop: 40
},
button: {
margin: theme.spacing.unit,
marginTop: theme.spacing.unit * 3
}
})
class UserSearch extends Component {
constructor (props) {
super(props)
this.state = {
alias: '',
firstName: '',
middleName: '',
lastName: ''
}
}
submitForm (e) {
e.preventDefault()
this.props.getUsersBySearchFields.variables.alias = this.state.alias
this.props.getUsersBySearchFields.variables.firstName = this.state.firstName
this.props.getUsersBySearchFields.variables.middleName = this.state.middleName
this.props.getUsersBySearchFields.variables.lastName = this.state.lastName
this.props.getUsersBySearchFields.refetch({})
}
handleTextField (e) {
/*
We will do some basic input validations here. If something is wrong we will turn on the error sign on the textfield.
*/
let value = e.target.value
switch (e.target.id) {
case 'alias':
if (value.length > 30) {
this.setState({aliasError: true})
} else {
this.setState({aliasError: false, alias: value})
}
break
case 'firstName':
if (value.length > 30) {
this.setState({firstNameError: true})
} else {
this.setState({firstNameError: false, firstName: value})
}
break
case 'middleName':
if (value.length > 30) {
this.setState({middleNameError: true})
} else {
this.setState({middleNameError: false, middleName: value})
}
break
case 'lastName':
if (value.length > 50) {
this.setState({lastNameError: true})
} else {
this.setState({lastNameError: false, lastName: value})
}
break
default:
}
}
selectText () {
if (this.props.selectButton === true) {
return (<dummy>{this.props.selectText}</dummy>)
} else {
return (<div />)
}
}
selectButton (user) {
if (this.props.selectButton === true) {
return (
<Button id={user.id} ref={user.id} color='primary' onClick={() => {
this.props.onSelect(user) // This sends the user to the parent component
}}>
Select
</Button>
)
} else {
return (<div />)
}
}
displayUsers () {
let data = this.props.getUsersBySearchFields
const { classes } = this.props
if (data.loading) {
return (<div> Loading Users... </div>)
} else {
if (data.usersSearch === undefined) {
return (<div> No Users to Display </div>)
} else {
return data.usersSearch.map(user => {
return (
<Grid key={user.id} item>
<Card className={classes.card} onClick={(e) => {
this.setState({ selected: user.id})
}
}>
<CardActionArea>
<CardMedia
className={classes.media}
image={PortraitImage}
title='User Profile'
/>
<CardContent>
<Typography gutterBottom variant='headline' component='h2'>
{user.alias}
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Grid container justify='center' spacing={8}>
<Grid item>
{this.selectButton(user)}
</Grid>
</Grid>
</CardActions>
</Card>
</Grid>
)
})
}
}
}
render () {
const { classes } = this.props
return (
<div>
<form onSubmit={this.submitForm.bind(this)}>
<Typography className={classes.formTypography} variant='body1' gutterBottom align='left'>
Use any of these fileds to search for users. {this.selectText()}
</Typography>
<TextField
error={this.state.aliasError}
id='alias'
type='text'
value={this.state.alias}
label='Alias'
className={classes.inputField}
onChange={this.handleTextField.bind(this)}
/>
<TextField
error={this.state.firstNameError}
id='firstName'
type='text'
value={this.state.firstName}
label='First Name'
className={classes.inputField}
onChange={this.handleTextField.bind(this)}
/>
<TextField
error={this.state.middleNameError}
id='middleName'
type='text'
value={this.state.middleName}
label='Middle Name'
className={classes.inputField}
onChange={this.handleTextField.bind(this)}
/>
<TextField
error={this.state.lastNameError}
id='lastName'
type='text'
value={this.state.lastName}
label='Last Name'
className={classes.inputField}
onChange={this.handleTextField.bind(this)}
/>
<Grid container justify='center' >
<Grid item>
<Button variant='contained' color='secondary' className={classes.button} onClick={this.submitForm.bind(this)}>Search</Button>
</Grid>
</Grid>
</form>
<Grid container className={classes.grid} justify='center' spacing={24}>
{this.displayUsers()}
</Grid>
</div>
)
}
}
export default compose(
graphql(getUsersBySearchFields, {name: 'getUsersBySearchFields'}),
withStyles(styles)
)(UserSearch) // This technique binds more than one query to a single component.
+16 -8
View File
@@ -4,14 +4,18 @@ import { withStyles } from '@material-ui/core/styles';
import AppBar from '@material-ui/core/AppBar';
import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';
import UpdateIcon from '@material-ui/icons/Create';
import ImageIcon from '@material-ui/icons/Wallpaper';
import ProfileSheetIcon from '@material-ui/icons/Create';
import ProfileImagesIcon from '@material-ui/icons/Wallpaper';
import YourReferrerIcon from '@material-ui/icons/AccessibilityNew';
import DescendentsIcon from '@material-ui/icons/DeviceHub';
import Typography from '@material-ui/core/Typography';
// Components
import UserUpdate from './UserUpdate';
import UserImages from './UserImages';
import ProfileSheet from './ProfileSheet';
import ProfileImages from './ProfileImages';
import YourReferrer from './YourReferrer';
import YourDescendents from './YourDescendents';
function TabContainer(props) {
return (
@@ -59,12 +63,16 @@ class UserTabs extends React.Component {
indicatorColor="primary"
textColor="primary"
>
<Tab label="Your User Profile" icon={<UpdateIcon />} />
<Tab label="Manage Images" icon={<ImageIcon />} />
<Tab label="Profile Sheet" icon={<ProfileSheetIcon />} />
<Tab label="Profile Images" icon={<ProfileImagesIcon />} />
<Tab label="Your Referrer" icon={<YourReferrerIcon />} />
<Tab label="Your Descendents" icon={<DescendentsIcon />} />
</Tabs>
</AppBar>
{value === 0 && <TabContainer><UserUpdate/></TabContainer>}
{value === 1 && <TabContainer><UserImages/></TabContainer>}
{value === 0 && <TabContainer><ProfileSheet/></TabContainer>}
{value === 1 && <TabContainer><ProfileImages/></TabContainer>}
{value === 2 && <TabContainer><YourReferrer/></TabContainer>}
{value === 3 && <TabContainer><YourDescendents/></TabContainer>}
</div>
);
}
+85
View File
@@ -0,0 +1,85 @@
import React, { Component } from 'react'
import {compose} from 'react-apollo'
// Materia UI
import { withStyles } from '@material-ui/core/styles'
import Typography from '@material-ui/core/Typography'
import Grid from '@material-ui/core/Grid'
import Paper from '@material-ui/core/Paper'
// components
import DescendentsTree from './DescendentsTree'
const styles = theme => ({
root: {
width: '50%',
flexGrow: 1,
padding: 10,
marginLeft: '25%',
marginTop: '2%'
},
typography: {
width: '80%',
marginLeft: '10%',
marginTop: 40,
marginBottom: 40
},
grid: {
paddingTop: '30',
marginTop: 30
}
})
class YourDescendents extends Component {
constructor (props) {
super(props)
this.defaultValuesSet = false
this.state = {
id: ''
}
}
componentWillMount () {
if (this.defaultValuesSet === false) {
let userData = localStorage.getItem('loggedInUser')
if (userData === 'undefined') { return }
let user = JSON.parse(userData)
this.defaultValuesSet = true
/* Now we are ready to set the initial state. */
this.setState({
id: user.id
})
}
}
render () {
const { classes } = this.props
return (
<Paper className={classes.root}>
<Typography className={classes.typography} variant='headline' gutterBottom>
Your Descendents
</Typography>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
These are your decendents within the project. Your children referred you as the one who brought them to the project, while
your grandchildren referred your children and so on.
</Typography>
<DescendentsTree userId={this.state.id} />
<Grid container className={classes.grid} justify='center' spacing={24} />
</Paper>
)
}
}
export default compose(
withStyles(styles)
)(YourDescendents) // This technique binds more than one query to a single component.
+146
View File
@@ -0,0 +1,146 @@
import React, { Component } from 'react'
import {graphql, compose} from 'react-apollo'
import {updateReferrerMutation} from '../queries/queries'
// components
import UserSearch from './UserSearch'
import UserProfile from './UserProfile'
// Material-ui
import { withStyles } from '@material-ui/core/styles'
import Paper from '@material-ui/core/Paper'
import Typography from '@material-ui/core/Typography'
const styles = theme => ({
root: {
width: '50%',
flexGrow: 1,
padding: 10,
marginLeft: '25%',
marginTop: '2%'
},
typography: {
width: '80%',
marginLeft: '10%',
marginTop: 40,
marginBottom: 40
},
button: {
margin: theme.spacing.unit,
marginTop: theme.spacing.unit * 3
},
inputField: {
width: '80%',
marginLeft: '10%',
marginTop: 25
}
})
class YourReferrer extends Component {
constructor (props) {
super(props)
this.defaultValuesSet = false
this.state = {
id: '',
referrerId: '',
firstNameError: false,
middleNameError: false,
lastNameError: false,
aliasError: false
}
}
userSelected (referrerUser) {
this.setState({referrerId: referrerUser.id})
this.props.updateReferrerMutation({
variables: {
id: this.state.id,
referrerId: referrerUser.id
}
})
/* Before we are done, we need to update the state of the local storage. */
let user = JSON.parse(localStorage.getItem('loggedInUser'))
user.referrerId = referrerUser.id
localStorage.setItem('loggedInUser', JSON.stringify(user))
}
renderMode () {
const { classes } = this.props
if (this.state.referrerId !== null) {
return (
<div>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
This is the user who introduced you to the project.
</Typography>
<UserProfile userId={this.state.referrerId} />
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
This information can not be changed.
</Typography>
</div>
)
} else {
return (
<div>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
We know that a group often becomes more intelligent when the number of people in the group increases.
To incentivize members of the community to invite more people to join we have developed this referral
program in which you can specify who referred you to the project, and see the members who pointed at
you as their referrer. Later this information will be available at your user profile and add to your
overall reputation within the project.
</Typography>
<UserSearch selectButton onSelect={this.userSelected.bind(this)} selectText="After that press the 'Select' button on the desired user to set it as your referrer. Bear in mind that this action can not be undone." />
</div>
)
}
}
componentWillMount () {
if (this.defaultValuesSet === false) {
let userData = localStorage.getItem('loggedInUser')
if (userData === 'undefined') { return }
let user = JSON.parse(userData)
this.defaultValuesSet = true
/* Now we are ready to set the initial state. */
this.setState({
id: user.id,
referrerId: user.referrerId
})
}
}
render () {
const { classes } = this.props
return (
<Paper className={classes.root}>
<Typography className={classes.typography} variant='headline' gutterBottom>
Your Referrer
</Typography>
{this.renderMode()}
</Paper>
)
}
}
export default compose(
graphql(updateReferrerMutation, {name: 'updateReferrerMutation'}),
withStyles(styles)
)(YourReferrer) // This technique binds more than one query to a single component.
-40
View File
@@ -1,40 +0,0 @@
import React from 'react';
import {
XYPlot,
XAxis,
YAxis,
HorizontalGridLines,
VerticalGridLines,
LineSeries
} from 'index';
const data = [];
for (let i = 0; i < 20; i++) {
const series = [];
for (let j = 0; j < 100; j++) {
series.push({x: j, y: (i / 10 + 1) * Math.sin(Math.PI * (i + j) / 50)});
}
data.push({color: i, key: i, data: series, opacity: 0.8});
}
export default class Example extends React.Component {
render() {
return (
<XYPlot
width={300}
height={300}
colorType="linear"
colorDomain={[0, 9]}
colorRange={['yellow', 'orange']}
>
<HorizontalGridLines />
<VerticalGridLines />
<XAxis />
<YAxis />
{data.map(props => <LineSeries {...props}/>)}
</XYPlot>
);
}
}
+21
View File
@@ -0,0 +1,21 @@
import NavBar from './navbar'
import Footer from './footer'
import Callback from './callback'
import Home from './home'
import About from './about'
import Dashboard from './dashboard'
import Teams from './teams'
import { theme, globalStyles } from './theme'
export {
NavBar,
Footer,
Callback,
Home,
About,
Dashboard,
Teams,
theme,
globalStyles
}
+21
View File
@@ -0,0 +1,21 @@
import NavBar from './navbar'
import Footer from './footer'
import Callback from './callback'
import Home from './home'
import About from './about'
import Dashboard from './dashboard'
import Teams from './teams'
import { theme, globalStyles } from './theme'
export {
NavBar,
Footer,
Callback,
Home,
About,
Dashboard,
Teams,
theme,
globalStyles
}
+95 -7
View File
@@ -16,7 +16,6 @@ const getUsersQuery = gql`
}
}
`
const getUserProfileQuery = gql`
query($id: ID){
user (id: $id){
@@ -26,8 +25,7 @@ query($id: ID){
middleName
lastName
bio
email
emailVerified
avatarHandle
role {
id
name
@@ -35,11 +33,11 @@ query($id: ID){
}
}
`
const getUserByAuthIdQuery = gql`
query($authId: String){
userByAuthId (authId: $authId){
id
referrerId
alias
firstName
middleName
@@ -50,13 +48,60 @@ query($authId: String){
isDeveloper
isDataAnalyst
isTrader
avatarHandle
avatarChangeDate
role {
id
}
}
}
`
const getUsersBySearchFields = gql`
query(
$alias: String,
$firstName: String,
$middleName: String,
$lastName: String
){
usersSearch (alias: $alias, firstName: $firstName, middleName: $middleName, lastName: $lastName){
id
alias
firstName
middleName
lastName
}
}
`
const getDescendentsQuery = gql`
query(
$id: String
){
descendents (id: $id){
id
alias
firstName
middleName
lastName
referrerId
descendents {
id
alias
firstName
middleName
lastName
referrerId
descendents {
id
alias
firstName
middleName
lastName
referrerId
}
}
}
}
`
const getRolesQuery = gql`
{
roles {
@@ -65,7 +110,6 @@ const getRolesQuery = gql`
}
}
`
const updateUserMutation = gql`
mutation(
$id: ID!,
@@ -96,4 +140,48 @@ mutation(
}
}
`
export {getUsersQuery, getUserByAuthIdQuery, getRolesQuery, updateUserMutation, getUserProfileQuery}
const updateReferrerMutation = gql`
mutation(
$id: ID!,
$referrerId:String!
)
{
updateUserReferrer (
id: $id,
referrerId:$referrerId
)
{
id
referrerId
}
}
`
const updateUserImagesMutation = gql`
mutation(
$id: ID!,
$avatarHandle:String,
$avatarChangeDate:String
)
{
updateUserImages (
id: $id,
avatarHandle:$avatarHandle,
avatarChangeDate: $avatarChangeDate
)
{
id
alias
}
}
`
export {
getUsersQuery,
getUserByAuthIdQuery,
getRolesQuery,
getUserProfileQuery,
getUsersBySearchFields,
getDescendentsQuery,
updateUserMutation,
updateReferrerMutation,
updateUserImagesMutation
}
+70
View File
@@ -0,0 +1,70 @@
import { createMuiTheme } from '@material-ui/core/styles'
export const theme = createMuiTheme({
palette: {
primary: { main: '#303036' }, // DARK.
secondary: { main: '#CC5835' } // RUSTED_RED.
},
typography: {
fontFamily: '"Saira","Saira Condenses", sans-serif'
},
overrides: {
Paper: {
root: {
backgroundColor: '#ffffff'
},
elevation: 0,
square: true
}
}
})
export const globalStyles = theme => ({
'@global': {
body: {
backgroundColor: theme.palette.common.white
}
},
appBar: {
position: 'relative'
},
toolbarTitle: {
flex: 1
},
layout: {
width: 'auto',
marginLeft: theme.spacing.unit * 3,
marginRight: theme.spacing.unit * 3,
[theme.breakpoints.up(900 + theme.spacing.unit * 3 * 2)]: {
width: 900,
marginLeft: 'auto',
marginRight: 'auto'
}
},
heroContent: {
maxWidth: 600,
margin: '0 auto',
padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px`
},
cardHeader: {
backgroundColor: theme.palette.grey[200]
},
cardPricing: {
display: 'flex',
justifyContent: 'center',
alignItems: 'baseline',
marginBottom: theme.spacing.unit * 2
},
cardActions: {
[theme.breakpoints.up('sm')]: {
paddingBottom: theme.spacing.unit * 2
}
},
footer: {
marginTop: theme.spacing.unit * 8,
borderTop: `1px solid ${theme.palette.divider}`,
padding: `${theme.spacing.unit * 6}px 0`
}
})
export default theme
+129
View File
@@ -0,0 +1,129 @@
import React from 'react'
import PropTypes from 'prop-types'
import { NavLink } from 'react-router-dom'
import { withStyles } from '@material-ui/core/styles'
import classNames from 'classnames'
import Typography from '@material-ui/core/Typography'
import Grid from '@material-ui/core/Grid'
import aalogo from '../../assets/logos/advanced-algos/aa-logo-vert.svg'
const styles = theme => ({
'@global': {
body: {
backgroundColor: theme.palette.common.white
}
},
layout: {
width: 'auto',
marginTop: theme.spacing.unit * 7,
marginLeft: theme.spacing.unit * 3,
marginRight: theme.spacing.unit * 3,
[theme.breakpoints.up(1200 + theme.spacing.unit * 3 * 2)]: {
width: 1200,
marginLeft: 'auto',
marginRight: 'auto'
}
},
footer: {
borderTop: `1px solid ${theme.palette.divider}`,
padding: `${theme.spacing.unit * 6}px 0`
},
footerContainer: {
marginRight: theme.spacing.unit * 8,
marginLeft: theme.spacing.unit * 8
},
footerLink: {
textDecoration: 'none'
}
})
const Footer = ({ classes }) => {
return (
<footer className={classNames(classes.footer, classes.layout)}>
<Grid
container
spacing={32}
justify='space-evenly'
className={classNames(classes.footerContainer)}
>
<Grid item xs>
<Typography variant='title' color='textPrimary' gutterBottom>
Pages
</Typography>
<NavLink to='/' className={classNames(classes.footerLink)}>
<Typography variant='subheading' color='textSecondary'>
Home
</Typography>
</NavLink>
<NavLink to='/browse' className={classNames(classes.footerLink)}>
<Typography variant='subheading' color='textSecondary'>
Users
</Typography>
</NavLink>
<NavLink to='/about' className={classNames(classes.footerLink)}>
<Typography variant='subheading' color='textSecondary'>
About
</Typography>
</NavLink>
</Grid>
<Grid item xs>
<a
href='https://t.me/advancedalgoscommunity'
target='_blank>'
className={classNames(classes.footerLink)}
>
<Typography variant='title' color='textPrimary' gutterBottom>
Support
</Typography>
</a>
<a
href='https://advancedalgos.net/documentation-quick-start.shtml'
target='_blank>'
className={classNames(classes.footerLink)}
>
<Typography variant='subheading' color='textSecondary'>
Documentation
</Typography>
</a>
<NavLink to='/' className={classNames(classes.footerLink)}>
<Typography variant='subheading' color='textSecondary'>
Telegram
</Typography>
</NavLink>
</Grid>
<Grid item xs>
<Typography variant='title' color='textPrimary' gutterBottom>
Modules
</Typography>
<NavLink to='/' className={classNames(classes.footerLink)}>
<Typography variant='subheading' color='textSecondary'>
Teams
</Typography>
</NavLink>
<NavLink to='/' className={classNames(classes.footerLink)}>
<Typography variant='subheading' color='textSecondary'>
Users
</Typography>
</NavLink>
<NavLink to='/' className={classNames(classes.footerLink)}>
<Typography variant='subheading' color='textSecondary'>
KeyVault
</Typography>
</NavLink>
</Grid>
<Grid item xs>
<NavLink to='/'>
<img alt='' src={aalogo} width={98} height={140} />
</NavLink>
</Grid>
</Grid>
</footer>
)
}
Footer.propTypes = {
classes: PropTypes.object.isRequired
}
export default withStyles(styles)(Footer)
+21
View File
@@ -0,0 +1,21 @@
// import NavBar from './navbar'
import Footer from './footer'
// import Callback from './callback'
// import Home from './home'
// import About from './about'
// import Dashboard from './dashboard'
// import Teams from './teams'
// import { theme, globalStyles } from './theme'
export {
// NavBar,
Footer
// Callback,
// Home,
// About,
// Dashboard,
// Teams,
// theme,
// globalStyles
}
+47
View File
@@ -0,0 +1,47 @@
import React from 'react'
import PropTypes from 'prop-types'
import { graphql } from 'react-apollo'
import LoggedInMenu from './LoggedInMenu'
import { GetCurrentMember } from '../../graphql/members'
import { isDefined } from '../../utils/js-helpers'
export const LoggedIn = props => {
let { data, user, auth } = props
console.log('LoggedIn :', data, user)
let displayName = 'No Display Name'
if (isDefined(user.alias)) {
displayName = user.alias
}
if (isDefined(user.nickname)) {
displayName = user.nickname
}
if (isDefined(user.firstName)) {
displayName = user.firstName
}
if (isDefined(user.firstName) && isDefined(user.lastName)) {
displayName = user.firstName + ' ' + user.lastName
}
return (
<div>
<p>
<LoggedInMenu menuLabel={displayName} auth={auth} />
</p>
</div>
)
}
LoggedIn.propTypes = {
data: PropTypes.object,
user: PropTypes.object.isRequired,
auth: PropTypes.object.isRequired
}
export default graphql(GetCurrentMember)(LoggedIn) // This binds the querty to the component
+77
View File
@@ -0,0 +1,77 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Button from '@material-ui/core/Button'
import Menu from '@material-ui/core/Menu'
import MenuItem from '@material-ui/core/MenuItem'
import { Link } from 'react-router-dom'
import ProfileIcon from '@material-ui/icons/Person'
import LogoutIcon from '@material-ui/icons/DirectionsWalk'
const UserLink = props => <Link to='/user' {...props} />
const LogoutLink = props => <Link to='/' {...props} />
class LoggedInUserMenu extends Component {
constructor (props) {
super(props)
this.handleMenu = this.handleMenu.bind(this)
this.handleClose = this.handleClose.bind(this)
this.handleLogout = this.handleLogout.bind(this)
this.state = {
menu: null
}
}
render () {
const { menuLabel } = this.props
return (
<React.Fragment>
<Button
aria-owns={this.state.open ? 'render-props-menu' : null}
aria-haspopup='true'
onClick={e => this.handleMenu(e)}
color='inherit'
>
{menuLabel}
</Button>
<Menu
id='render-props-menu'
anchorEl={this.state.menu}
open={Boolean(this.state.menu)}
onClose={this.handleClose}
>
<MenuItem onClick={this.handleClose} component={UserLink}>
<ProfileIcon />
<div>Profile</div>
</MenuItem>
<MenuItem onClick={this.handleLogout} component={LogoutLink}>
<LogoutIcon />
<div>Logout</div>
</MenuItem>
</Menu>
</React.Fragment>
)
}
handleMenu (e) {
this.setState({ menu: e.currentTarget })
}
handleClose () {
this.setState({ menu: null })
}
handleLogout () {
this.props.auth.logout()
this.setState({ menu: null })
}
}
LoggedInUserMenu.propTypes = {
menuLabel: PropTypes.string.isRequired,
auth: PropTypes.object.isRequired
}
export default LoggedInUserMenu
+15
View File
@@ -0,0 +1,15 @@
import React from 'react'
import PropTypes from 'prop-types'
import Button from '@material-ui/core/Button'
export const LoggedOut = ({ auth }) => (
<div onClick={() => auth.login()}>
<Button color='inherit'>Login / Sign up</Button>
</div>
)
LoggedOut.propTypes = {
auth: PropTypes.object.isRequired
}
export default LoggedOut // This binds the querty to the component
+141
View File
@@ -0,0 +1,141 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { withStyles } from '@material-ui/core/styles'
import AppBar from '@material-ui/core/AppBar'
import Toolbar from '@material-ui/core/Toolbar'
import Typography from '@material-ui/core/Typography'
import IconButton from '@material-ui/core/IconButton'
import Button from '@material-ui/core/Button'
// icons
import HomeIcon from '@material-ui/icons/Home'
import DashboardIcon from '@material-ui/icons/Dashboard'
import { Link } from 'react-router-dom'
import { getItem } from '../../utils/local-storage'
// components
import { LoggedIn } from './LoggedIn'
import { LoggedOut } from './LoggedOut'
import AALogo from '../../assets/logos/advanced-algos/aa-logo-dark.svg'
const AboutLink = props => <Link to='/about' {...props} />
const TeamsLink = props => <Link to='/teams' {...props} />
const DashboardLink = props => <Link to='/dashboard' {...props} />
const HomeLink = props => <Link to='/' {...props} />
const styles = theme => ({
'@global': {
body: {
backgroundColor: theme.palette.common.white
}
},
root: {
flexGrow: 1
},
colorDefault: {
color: '#000'
},
flex: {
flexGrow: 1
},
toolbarTitle: {
flex: 1
},
menuButton: {
marginLeft: -12,
marginRight: 20
},
appBar: {
position: 'relative'
},
img: {
margin: 20,
display: 'block',
maxWidth: 240,
maxHeight: 48
}
})
class NavBar extends Component {
constructor (props) {
super(props)
this.state = {
user: null,
open: false
}
}
async componentDidMount () {
const user = await getItem('user')
console.log('NavBar CDM: ', user, this.state)
this.setState({ user })
}
render () {
let { classes, auth } = this.props
let user = JSON.parse(this.state.user)
return (
<div className={classes.root}>
<AppBar
position='static'
classes={{ root: classes.appBar, colorDefault: classes.colorDefault }}
>
<Toolbar>
<img className={classes.img} src={AALogo} alt='Advanced Algos' />
<Typography
variant='title'
color='inherit'
className={classes.toolbarTitle}
>
Teams
</Typography>
<IconButton
className={classes.menuButton}
color='inherit'
title='Home'
component={HomeLink}
>
<HomeIcon />
</IconButton>
<Button component={TeamsLink} color='inherit'>
Teams
</Button>
<Button component={AboutLink} color='inherit'>
About
</Button>
{this.state.user !== undefined && this.state.user !== null ? (
<React.Fragment>
<IconButton
className={classes.menuButton}
color='inherit'
title='Dashboard'
component={DashboardLink}
>
<DashboardIcon />
</IconButton>
<LoggedIn user={user} auth={auth} styles={styles} />
</React.Fragment>
) : (
<LoggedOut auth={auth} styles={styles} />
)}
</Toolbar>
</AppBar>
</div>
)
}
}
NavBar.propTypes = {
classes: PropTypes.object.isRequired,
auth: PropTypes.object.isRequired
}
export default withStyles(styles)(NavBar)
+5 -1
View File
@@ -6,6 +6,8 @@ const Schema = mongoose.Schema
const userSchema = new Schema({
authId: String,
referrerId: String,
creationDate: String,
alias: String,
firstName: String,
middleName: String,
@@ -16,7 +18,9 @@ const userSchema = new Schema({
isDeveloper: Boolean,
isTrader: Boolean,
isDataAnalyst: Boolean,
roleId: String
roleId: String,
avatarHandle: String,
avatarChangeDate: String
})
global.UserSchema = global.UserSchema || mongoose.model('User', userSchema)
+99
View File
@@ -30,6 +30,7 @@ const UserType = new GraphQLObjectType({
fields: () => ({
id: { type: GraphQLID},
authId: { type: GraphQLString},
referrerId: {type: GraphQLString},
alias: {type: GraphQLString},
firstName: {type: GraphQLString},
middleName: {type: GraphQLString},
@@ -40,6 +41,8 @@ const UserType = new GraphQLObjectType({
isDeveloper: {type: GraphQLInt},
isTrader: {type: GraphQLInt},
isDataAnalyst: {type: GraphQLInt},
avatarHandle: {type: GraphQLString},
avatarChangeDate: {type: GraphQLString},
role: {
type: RoleType,
resolve (parent, args) {
@@ -49,6 +52,24 @@ const UserType = new GraphQLObjectType({
})
})
const DescendentType = new GraphQLObjectType({
name: 'Descendent',
fields: () => ({
id: { type: GraphQLID},
referrerId: {type: GraphQLString},
alias: {type: GraphQLString},
firstName: {type: GraphQLString},
middleName: {type: GraphQLString},
lastName: {type: GraphQLString},
descendents: {
type: new GraphQLList(DescendentType),
resolve (parent, args) {
return User.find({referrerId: parent.id})
}
}
})
})
const RoleType = new GraphQLObjectType({
name: 'Role',
fields: () => ({
@@ -127,6 +148,33 @@ const RootQuery = new GraphQLObjectType({
resolve (parent, args) {
return roles
}
},
usersSearch: {
type: new GraphQLList(UserType),
args: {alias: {type: GraphQLString}, firstName: {type: GraphQLString}, middleName: {type: GraphQLString}, lastName: {type: GraphQLString}},
resolve (parent, args) {
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> RootQuery -> usersSearch -> resolve -> Entering function.') }
let mongoQuery = { $or: [] }
if (args.alias !== null && args.alias !== '') { mongoQuery.$or.push({alias: args.alias}) }
if (args.firstName !== null && args.firstName !== '') { mongoQuery.$or.push({firstName: args.firstName}) }
if (args.middleName !== null && args.middleName !== '') { mongoQuery.$or.push({middleName: args.middleName}) }
if (args.lastName !== null && args.lastName !== '') { mongoQuery.$or.push({lastName: args.lastName}) }
if (mongoQuery.$or.length === 0) { mongoQuery = {} }
return User.find(mongoQuery)
}
},
descendents: {
type: new GraphQLList(DescendentType),
args: {id: {type: GraphQLString}},
resolve (parent, args) {
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> RootQuery -> descendents -> resolve -> Entering function.') }
return User.find({referrerId: args.id})
}
}
}
})
@@ -195,6 +243,45 @@ const Mutation = new GraphQLObjectType({
roleId: args.roleId
}
return User.update(key, updatedUser)
}
},
updateUserImages: {
type: UserType,
args: {
id: {type: new GraphQLNonNull(GraphQLID)},
avatarHandle: {type: GraphQLString},
avatarChangeDate: {type: GraphQLString}
},
resolve (parent, args) {
let key = {
_id: args.id
}
let updatedUser = {
avatarHandle: args.avatarHandle,
avatarChangeDate: args.avatarChangeDate
}
return User.update(key, updatedUser)
}
},
updateUserReferrer: {
type: UserType,
args: {
id: {type: new GraphQLNonNull(GraphQLID)},
referrerId: {type: GraphQLString}
},
resolve (parent, args) {
let key = {
_id: args.id,
referrerId: null
}
let updatedUser = {
referrerId: args.referrerId
}
return User.update(key, updatedUser)
}
}
@@ -345,9 +432,21 @@ function authenticate (encodedToken, callBackFunction) {
return
}
let localDate = new Date()
let creationDate = new Date(Date.UTC(
localDate.getUTCFullYear(),
localDate.getUTCMonth(),
localDate.getUTCDate(),
localDate.getUTCHours(),
localDate.getUTCMinutes(),
localDate.getUTCSeconds(),
localDate.getUTCMilliseconds())
)
let newUser = new User({
alias: alias,
authId: authId,
creationDate: creationDate.toISOString(),
email: email,
emailVerified: emailVerified,
roleId: '1'