From 97ff781c11bf6c38d615d0b1a8144b9fefe7e1a7 Mon Sep 17 00:00:00 2001 From: Barry Low Date: Wed, 10 Oct 2018 22:07:28 -0700 Subject: [PATCH] Incorporate apollo, material-ui and auth0 --- client/package.json | 2 + client/src/App.js | 50 +++- .../assets/advanced-algos/aa-logo-dark.svg | 1 + .../assets/advanced-algos/aa-logo-vert.svg | 1 + client/src/assets/advanced-algos/aa-logo.png | Bin 0 -> 4770 bytes .../favicon/android-chrome-192x192.png | Bin 0 -> 2515 bytes .../favicon/android-chrome-512x512.png | Bin 0 -> 6543 bytes .../favicon/apple-touch-icon.png | Bin 0 -> 3064 bytes .../advanced-algos/favicon/browserconfig.xml | 9 + .../advanced-algos/favicon/favicon-16x16.png | Bin 0 -> 502 bytes .../advanced-algos/favicon/favicon-32x32.png | Bin 0 -> 758 bytes .../assets/advanced-algos/favicon/favicon.ico | Bin 0 -> 15086 bytes .../advanced-algos/favicon/html_code.html | 9 + .../advanced-algos/favicon/mstile-150x150.png | Bin 0 -> 2535 bytes .../favicon/safari-pinned-tab.svg | 1 + .../advanced-algos/favicon/site.webmanifest | 19 ++ client/src/auth/Auth0.js | 7 + client/src/auth/index.js | 256 ++++++++++++++++++ client/src/graphql/apollo.js | 113 ++++++++ client/src/index.js | 4 +- client/src/styles/index.js | 72 +++++ client/src/utils/js-helpers.js | 70 +++++ client/src/utils/local-storage.js | 9 + client/src/views/callback/index.js | 0 client/src/views/footer/index.js | 160 +++++++++++ client/src/views/header/LoggedIn.js | 47 ++++ client/src/views/header/LoggedInMenu.js | 77 ++++++ client/src/views/header/LoggedOut.js | 0 client/src/views/header/index.js | 141 ++++++++++ client/src/views/home/index.js | 61 +++++ client/src/views/index.js | 6 + 31 files changed, 1101 insertions(+), 14 deletions(-) create mode 100644 client/src/assets/advanced-algos/aa-logo-dark.svg create mode 100644 client/src/assets/advanced-algos/aa-logo-vert.svg create mode 100644 client/src/assets/advanced-algos/aa-logo.png create mode 100644 client/src/assets/advanced-algos/favicon/android-chrome-192x192.png create mode 100644 client/src/assets/advanced-algos/favicon/android-chrome-512x512.png create mode 100644 client/src/assets/advanced-algos/favicon/apple-touch-icon.png create mode 100644 client/src/assets/advanced-algos/favicon/browserconfig.xml create mode 100644 client/src/assets/advanced-algos/favicon/favicon-16x16.png create mode 100644 client/src/assets/advanced-algos/favicon/favicon-32x32.png create mode 100644 client/src/assets/advanced-algos/favicon/favicon.ico create mode 100644 client/src/assets/advanced-algos/favicon/html_code.html create mode 100644 client/src/assets/advanced-algos/favicon/mstile-150x150.png create mode 100644 client/src/assets/advanced-algos/favicon/safari-pinned-tab.svg create mode 100644 client/src/assets/advanced-algos/favicon/site.webmanifest create mode 100644 client/src/auth/Auth0.js create mode 100644 client/src/auth/index.js create mode 100644 client/src/graphql/apollo.js create mode 100644 client/src/styles/index.js create mode 100644 client/src/utils/js-helpers.js create mode 100644 client/src/utils/local-storage.js create mode 100644 client/src/views/callback/index.js create mode 100644 client/src/views/footer/index.js create mode 100644 client/src/views/header/LoggedIn.js create mode 100644 client/src/views/header/LoggedInMenu.js create mode 100644 client/src/views/header/LoggedOut.js create mode 100644 client/src/views/header/index.js create mode 100644 client/src/views/home/index.js create mode 100644 client/src/views/index.js diff --git a/client/package.json b/client/package.json index 26958c2e1..38b4686d6 100644 --- a/client/package.json +++ b/client/package.json @@ -62,6 +62,8 @@ "dependencies": { "@advancedalgos/key-vault-client": "0.0.5", "@advancedalgos/teams-client": "0.0.8", + "@material-ui/core": "^3.2.0", + "@material-ui/icons": "^3.0.1", "babel-polyfill": "^6.26.0", "react": "^16.5.2", "react-dom": "^16.5.2", diff --git a/client/src/App.js b/client/src/App.js index 5eb065122..3d9730629 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -1,20 +1,46 @@ +import { ApolloProvider } from 'react-apollo' import React, { Component } from 'react' import { Route, BrowserRouter, Switch } from 'react-router-dom' -import App from '@advancedalgos/teams-client' -import App2 from '@advancedalgos/key-vault-client' +import MuiThemeProvider from '@material-ui/core/styles/MuiThemeProvider' +import CssBaseline from '@material-ui/core/CssBaseline' +import { withStyles } from '@material-ui/core/styles' +import { theme, globalStyles } from './styles' -export const Master = () => ( +import client from './graphql/apollo' +import Auth from './auth' + +import { Header, Footer, Home, Callback } from './views' + +import Teams from '@advancedalgos/teams-client' +import KeyVault from '@advancedalgos/key-vault-client' + +export const auth = new Auth( + result => console.log('auth result', result), + client +) + +export const MasterApp = () => ( - - - - + + + +
+
+ + + } + /> + + +
+
+
+
) -export const Temporary = () =>( -
Hello Advanced Alogs!
-) - -export default Master +export default withStyles(globalStyles)(MasterApp) diff --git a/client/src/assets/advanced-algos/aa-logo-dark.svg b/client/src/assets/advanced-algos/aa-logo-dark.svg new file mode 100644 index 000000000..479feeb86 --- /dev/null +++ b/client/src/assets/advanced-algos/aa-logo-dark.svg @@ -0,0 +1 @@ +aa-logo-dark \ No newline at end of file diff --git a/client/src/assets/advanced-algos/aa-logo-vert.svg b/client/src/assets/advanced-algos/aa-logo-vert.svg new file mode 100644 index 000000000..442e9a7fd --- /dev/null +++ b/client/src/assets/advanced-algos/aa-logo-vert.svg @@ -0,0 +1 @@ +aa-logo-vert \ No newline at end of file diff --git a/client/src/assets/advanced-algos/aa-logo.png b/client/src/assets/advanced-algos/aa-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9701ee1c0e1858370837bc61930333be69bc4cd6 GIT binary patch literal 4770 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 CP}HCR literal 0 HcmV?d00001 diff --git a/client/src/assets/advanced-algos/favicon/android-chrome-192x192.png b/client/src/assets/advanced-algos/favicon/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..150043a067d25f23a50da98a6210b918f475fc2f GIT binary patch literal 2515 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 K(680Q#rzwV-;{R% literal 0 HcmV?d00001 diff --git a/client/src/assets/advanced-algos/favicon/android-chrome-512x512.png b/client/src/assets/advanced-algos/favicon/android-chrome-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..d98b9ce8dfd54d6032578443e2fbcd100ded89d3 GIT binary patch literal 6543 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 literal 0 HcmV?d00001 diff --git a/client/src/assets/advanced-algos/favicon/apple-touch-icon.png b/client/src/assets/advanced-algos/favicon/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..95ec62746f406ac4380317ecac6e421082e89075 GIT binary patch literal 3064 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 + + + + + #da532c + + + diff --git a/client/src/assets/advanced-algos/favicon/favicon-16x16.png b/client/src/assets/advanced-algos/favicon/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..99bda00afe0b53c6844ec2924ab42b8084224fe3 GIT binary patch literal 502 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstUx|vage(c z!@6@aFM*td0G|-oC+?P*$S1Q9Q;z5jjV*#G}eH@M4% zFtxQ5G*3A7;>)7tYEs%i8|0gcj+?SRpWd`F!giHnjIP?6-Q0Y+&Og@|xz``q@?w{_ za)q+8n&F33wH*DlW04+@&l#sfR-UsOAu{|Cy&nOiTJ zTUc4xd$I_#u!2j2$>9`c<;@`qr*B+2apcSqnIr6{8$1?x=`p+#7cBYYWI7dS1%s!n KpUXO@geCw#&&NOj literal 0 HcmV?d00001 diff --git a/client/src/assets/advanced-algos/favicon/favicon-32x32.png b/client/src/assets/advanced-algos/favicon/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..08c2369b05c014d615766ea699a4a355d454ed25 GIT binary patch literal 758 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyEa{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaNh0(?STpSW9MBA?7cOhHmb9xo5e1==E8666=m`18dn79M*BrayZh-qaTI zmCkr?yu4|4beYn`w#~+>nYKWut@Cto46!(!8{D~VwE_=IWK-Af(%gUl&F{0ksr?$_ zr+wPT$%wP7&Q0OE$+VDrE7=c)Wysog^s~4=U$OJaqVqlR{CUgoZFtuEhS~9{f=x__ zzg$z!RIZd6$$i0hKboDLCid*mUjdy`^;UrmH|B9nTb6VvT+>^79Y;AZK-eEt`*#*_ z8%4Bi|HPQ_V54Hq&#(4p70!K|soiq_#Uyd3d2jyP9N1xb_Qb~4v)n?GD?$s31&_Rn z?b^m$AimK^^ZZLCmRk(dWhOSvNshGMx%hWXVZq8u8J)<2#QymSN7YX_=B$dll*51U zV?DFAedaZb8O<}^8$L9$Ni5g2G?Mn7lyP*|5do*W!e_IK7HT~U{WA5;CxJ^oSDtH3 zy&gHqVQy#IOvR2Tcb;AH7Mr^+=&5Lz%H-(RS9l)2I_dEC!Tu~Z=jYe|t)KL&Xz7Z2 z+2;Ji;jdSAPq7WYy|?GtquMe*ld0cw3)key-sW56Iz@Y_y%|?LOY5=&S45STif5)3 zE2{|A_$zCj`&tvSa%G)d-%_7mBs%pCTA7B)RSA|5B1SOU$6cpvBW#*(RlvEa^Dr6RvBr`Bn%z6BYhodk| zL*tbH=`)^BgBX~Vx%HB{g_VW9CyOu(E4Vb698O_Y-W;NE`o@(LN6s9PIl_Lr!DE4! a9>Xhf!IDo-rc;4dFnGH9xvX` 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 literal 0 HcmV?d00001 diff --git a/client/src/assets/advanced-algos/favicon/html_code.html b/client/src/assets/advanced-algos/favicon/html_code.html new file mode 100644 index 000000000..a66b72bb6 --- /dev/null +++ b/client/src/assets/advanced-algos/favicon/html_code.html @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/client/src/assets/advanced-algos/favicon/mstile-150x150.png b/client/src/assets/advanced-algos/favicon/mstile-150x150.png new file mode 100644 index 0000000000000000000000000000000000000000..78a06c05a5974bb75c8c71e99d32a960ed0d6497 GIT binary patch literal 2535 zcmbVO`8OMg8coN(jU}Z)6ji&#T7+UOwM&R-il%Msp_ZtN3?4JVW?uxqLio^f-zwl8q z#N}s*R16aC3DDTM#&<&I;Fsf>f%92Zl3Pq%MMXORAV_zzvqmLMt(UW2OlygzQ^ok# zcDYB29Hl6!znJjpQl5rL@+tFhE)kt}KP^r6pXUD#g1zPlTO9o)3Brp$Wrf1Y_9^Yh z`Yt6Fx7}?Q|B6u~##hdWf73hn&6`G6Zo^KrpC3Jd7LmN_1cHZOhSk5GK3_GHL55qH z`cAXPzDNWpCaHy@D#v^_)E6w#8W~ivz%MZ?Uk{lU)MHd`}eF4C_;ZV==bjlUP~6d^RNG~vN^bafSL>y zl1ZJs5id)T=?)#iFjq=5gr?=mp@sh07hTZPp_zh1l{U+gy-!OwEi~Mpw@L&U`?8BO zgj~IcI~iu4?6>bZUUW%H;Z%#v&f4>+dWa=d`m1G47|*gt8~977J@l7lWiIVHY-nPR zmFO^1ShDcxI%(6Uezd3%Dqyi5qucM31I}-pT~_`)j%)^_)W^9McAz4ejz-YA1y4Dt z^`@JxSWvL;UdVCER%GU=U3D+XP41je=?iU6I~byC6bxg46iEoZ&vbp6H4~!Tx_IX& z-xFH2S!GADXEZ$cJdp`3N2IDd*hmVmuwPd{Appeu9oK5r?7PEWDE6S`UlUEh;e5LteoLP zwrwr9_uw-17+4^);`EW)-ADMV4ttYeRL;=Wb=2K`m@d*hxpZ2V39#VQP%4hrC+OZ; z_4#sRE9GMDhl`1VJNdKt2F1E03ght6gYyEhcjG7`8w>WSc95vztlaY=icleZHN@D_lrM!2_0dsHTaZ&UVOsVzOUZ@4;3v{`Ax_MwZ?1;z;`yJE%3R z_#UmYl6lQRdb6tfwu-5F=;M;`h__hBqvT8Y0xqSVgzkLHXbyV zASR@LIj#>8_&3e)HAPTT zjjNR#Gx-8VZfTx!_A8qveWC0Gzz;?eo~3$C*5>-C8)oLZ&#&3%1$xLoT^)+^!B_NI zHfZXP0Oclf1!%vsUp31pqh3QwVhy$!#HPuV66FrmNVRTz-Ix8ZKay+9SZ9j+v|)M_ zM!DQpRS`tuZ5h15Yqa;fhyUkUK%OrD=2X}@sgZoGb(kuCIl&qEG}lP1dmM|n`CdM_ z#4C)6t95i<0+PGe_H49>;+dRW{d(YG9-bM-n_y6zNIR$m<<7?_J6ozlSWem0E_W4+ zz*}*Oor#x%OLBJ}+QJ&-w4U`f;=o` zGmVp>9e>(hHFi`Ju0(7wtcFZ9uR`m4<$v$|wP;uISphRyBh-F4fcC8`X7`8+uBa$> z?-&k@+-fU^8osl_=q$6U=M20d*@WmS4t~nYSiDQ3%1&*9p4>9p4g_drZEjH@kn%^DRp|L@t;SF4;|-#3RZB|~mb#~MBQmPPN+zbl z>84<^>ZXVyjI9r|*g$w{Lgt6*qu&Vpb6w5pM!9XGu(H$JTYZKUM5D*s6iXwB z!nS+xaF9t$E3l=;L1OUC>zoF)Gok4N36~h<=sXvr*1oIB)n}c$2HrgXK=L1V?sTvG z10vjVYr4)>^-++VW%i2y_)!XH;2PQN3Rk=+E6#5qx`>h5 zc(NCi6>QNoGrghaOLZu{Fe@1-T@i9t>rQcxLDIYD@+I<|$0`Gya4ybz zO)1G6xS|gHjA7{7TdaJ$d*=px_1?B~C-Wk+_DFpN;o2Q7`=}^Qj@MW%VL5U0!*8l+@*M5#LB{do6)Vsx_4tE?=kT=p zj6^=+y0DLSD`F0#sH(^SB|sv5AHNSsj8yXKFhp#W~nyE6w#@Xf`g~D?mYziJt=x|@U2QehPNPZ8LD3U87J+aFBsP#WO zF)E`5yWM;BOB1B&DW%9Z+-U)`MS|wVcwn0QBhTZOZq&VXqNEO`A zv!nQT?g|2H~y;D#av51uEg9V*CMsgtGZ \ No newline at end of file diff --git a/client/src/assets/advanced-algos/favicon/site.webmanifest b/client/src/assets/advanced-algos/favicon/site.webmanifest new file mode 100644 index 000000000..002445914 --- /dev/null +++ b/client/src/assets/advanced-algos/favicon/site.webmanifest @@ -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" +} diff --git a/client/src/auth/Auth0.js b/client/src/auth/Auth0.js new file mode 100644 index 000000000..37d937578 --- /dev/null +++ b/client/src/auth/Auth0.js @@ -0,0 +1,7 @@ +export const AUTH_CONFIG = { + api_audience: process.env.AUTH0_AUDIENCE, + domain: process.env.AUTH0_DOMAIN, + clientId: process.env.AUTH0_CLIENTID, + callbackUrl: process.env.AUTH0_CALLBACK_URL, + logoutUrl: process.env.AUTH0_LOGOUT_URL +} diff --git a/client/src/auth/index.js b/client/src/auth/index.js new file mode 100644 index 000000000..1c3fbfa80 --- /dev/null +++ b/client/src/auth/index.js @@ -0,0 +1,256 @@ +import Auth0Lock from 'auth0-lock' +import gql from 'graphql-tag' + +import { getItem, setItem, removeItem } from '../utils/local-storage' +import { validObject, deleteCookie } from '../utils/js-helpers' + +import { client } from '../App' + +import { AUTH_CONFIG } from './Auth0' // create by renaming Auth0.sample.js to Auth0.js and setting vars + +const AUTHENTICATE = gql` + mutation authenticate($idToken: String!) { + authenticate(idToken: $idToken) { + alias + authId + } + } +` + +const VERIFY_TEAM_INVITE = gql` + mutation verifyTeamInvite($token: String!) { + verifyTeamInvite(token: $token) { + email + team { + slug + } + } + } +` + +export const defaultOptions = { + oidcConformant: true, + autoclose: true, + auth: { + sso: true, + redirectUrl: window.location.origin + '/callback', + responseType: 'token id_token', + audience: `${AUTH_CONFIG.api_audience}`, + params: { + scope: `openid profile email user_metadata app_metadata picture` + } + } +} + +export const inviteOptions = { + oidcConformant: true, + autoclose: false, + allowedConnections: ['Username-Password-Authentication'], + allowShowPassword: true, + auth: { + sso: false, + redirectUrl: window.location.origin + '/callback', + responseType: 'token id_token', + audience: `${AUTH_CONFIG.api_audience}`, + params: { + state: '', + scope: `email` + } + }, + prefill: { email: '' } +} + +let lock = new Auth0Lock(AUTH_CONFIG.clientId, AUTH_CONFIG.domain, defaultOptions) + +class Auth { + constructor (cb, apolloClient) { + this.handleAuthentication() + // binds functions to keep this context + this.apolloClient = apolloClient + this.cb = cb.bind(this) + this.login = this.login.bind(this) + this.loginInvite = this.loginInvite.bind(this) + this.logout = this.logout.bind(this) + this.isAuthenticated = this.isAuthenticated.bind(this) + this.checkSession = this.checkSession.bind(this) + } + + login () { + // Call the show method to display the widget. + lock.show() + } + + async loginInvite (jwt) { + let email + let team + try { + const data = await client.mutate({ + mutation: VERIFY_TEAM_INVITE, + variables: { token: jwt } + }) + + console.log('loginInvite auth: ', await data.data.verifyTeamInvite) + setItem('invite', JSON.stringify(data.data.verifyTeamInvite)) + + email = data.data.verifyTeamInvite.email + team = data.data.verifyTeamInvite.team.slug + } catch (err) { + return console.log('loginInvite err: ', err) + } + inviteOptions.prefill.email = email + inviteOptions.auth.params.state = `${email}|${team}` + let lockInvite = new Auth0Lock(AUTH_CONFIG.clientId, AUTH_CONFIG.domain, inviteOptions) + lockInvite.show() + } + + handleAuthentication () { + // Add a callback for Lock's `authenticated` event + lock.on('authenticated', this.setSession.bind(this)) + // Add a callback for Lock's `authorization_error` event + lock.on('authorization_error', err => { + const data = { status: `error`, errMessage: err.error } + this.cb(data) + }) + } + + checkSession () { + return new Promise((resolve, reject) => { + // Add a callback for Lock's `authenticated` event + lock.checkSession( + { + responseType: 'token id_token', + audience: AUTH_CONFIG.api_audience, + scope: + 'openid email profile read:teams write:teams read:member write:member', + connection: 'github', + prompt: 'none' + }, + function (err, authResult) { + if (!err) { + resolve(authResult) + } else { + reject(err) + } + } + ) + }) + } + + setSession (authResult) { + if (authResult && authResult.accessToken && authResult.idToken) { + // Set the time that the access token will expire at + let expiresAt = JSON.stringify( + authResult.expiresIn * 1000 + new Date().getTime() + ) + setItem('access_token', authResult.accessToken) + setItem('id_token', authResult.idToken) + setItem('expires_at', expiresAt) + const data = { + status: `success`, + accessToken: authResult.accessToken, + idToken: authResult.idToken, + expiresAt + } + console.log('setSession idTokenPayload: ', authResult.idTokenPayload) + + this.signinOrCreateAccount({ ...data }) + this.cb(data) + const user = { + authId: authResult.idTokenPayload.sub, + alias: authResult.idTokenPayload.nickname + } + setItem('user', JSON.stringify(user)) + if (window.location.href.includes(`callback`)) { + // window.location.href = '/dashboard' + } + return true + } + } + + async signinOrCreateAccount ({ accessToken, idToken, expiresAt }) { + try { + const data = await client.mutate({ + mutation: AUTHENTICATE, + variables: { idToken } + }) + + const user = { + authId: data.data.authenticate.authId, + alias: data.data.authenticate.alias + } + setItem('user', JSON.stringify(user)) + if (window.location.href.includes(`callback`)) { + window.location.href = '/dashboard' + } + return data + } catch (err) { + return console.log('Sign in or create account error: ', err) + } + } + + logout () { + // Clear access token and ID token from local storage + removeItem('access_token') + removeItem('id_token') + removeItem('expires_at') + removeItem('authUser') + removeItem('auth0.ssodata') + window.localStorage.clear() + deleteCookie('ajs_anonymous_id') + deleteCookie('ajs_user_id') + deleteCookie('current_tenant') + + lock.logout({ returnTo: AUTH_CONFIG.logoutUrl }) + } + + async isAuthenticated () { + // check session and run Auth0 SS0 + const getUser = await getItem('authUser') + const getExpires = await getItem('expires_at') + let user = JSON.parse(getUser) + + if (new Date().getTime() < getExpires * 1000) { + console.log( + 'handleAuth.user exp: ', + user, + getExpires, + window.location.href + ) + + return user + } + + const checkSSO = await this.checkSession() + .then(result => { + console.log('handleAuth.checksessions: ', result) + const user = { + authId: result.idTokenPayload.sub, + alias: result.idTokenPayload.nickname + } + setItem('authUser', JSON.stringify(user)) + // user confirmed, log into client + this.setSession(result) + return result.idTokenPayload + }) + .catch(err => { + if (err.error === 'login_required') { + // If graphql error, update session + // otherwise send to login + // return this.login() + } + return err + }) + + if (/manage|profile|create|dashboard/.test(window.location.href) && !user) { + this.login() + } + + if (validObject(checkSSO, 'error')) { + return false + } else { + return checkSSO + } + } +} + +export default Auth diff --git a/client/src/graphql/apollo.js b/client/src/graphql/apollo.js new file mode 100644 index 000000000..d1a7e7b00 --- /dev/null +++ b/client/src/graphql/apollo.js @@ -0,0 +1,113 @@ +import { ApolloClient } from 'apollo-client' +import { HttpLink } from 'apollo-link-http' +import { InMemoryCache } from 'apollo-cache-inmemory' +import { ApolloLink, split, Observable } from 'apollo-link' +import { onError } from 'apollo-link-error' +import { setContext } from 'apollo-link-context' +import { WebSocketLink } from 'apollo-link-ws' +import { SubscriptionClient } from 'subscriptions-transport-ws' +import { getMainDefinition } from 'apollo-utilities' + +import { getItem } from './utils/local-storage' + +const graphqlEndpoint = + process.env.NODE_ENV === 'production' + ? process.env.PROD_GRAPHQL + : process.env.DEV_GRAPHQL + +const wsUri = graphqlEndpoint.replace(/^http/, 'ws') + +const globalVar = + typeof global !== 'undefined' + ? global + : typeof window !== 'undefined' + ? window + : {} +const webSocketImpl = globalVar.WebSocket || globalVar.MozWebSocket + +const wsClient = new SubscriptionClient( + wsUri, + { + reconnect: true + }, + webSocketImpl +) + +wsClient.onDisconnected(() => { + // console.log('onDisconnected') +}) + +wsClient.onReconnected(() => { + // console.log('onReconnected') +}) + +const httpLink = new HttpLink({ uri: graphqlEndpoint }) + +const link = split( + ({ query }) => { + const { kind, operation } = getMainDefinition(query) + return kind === 'OperationDefinition' && operation === 'subscription' + }, + new WebSocketLink(wsClient), + httpLink +) + +const authRetryLink = onError( + ({ graphQLErrors, networkError, operation, forward }) => { + if (graphQLErrors) { + // User access token has expired + // console.log('authLink: ', graphQLErrors) // check for error message to intercept and resend with Auth0 access token + if (graphQLErrors[0].message === 'Not logged in') { + // We assume we have auth0 access token needed to run the async request + // Let's refresh token through async request + return new Observable(observer => { + getItem('access_token') + .then(accessToken => { + operation.setContext(({ headers = {} }) => ({ + headers: { + // Re-add old headers + ...headers, + // Switch out old access token for new one + Authorization: `Bearer ${accessToken}` || null + } + })) + }) + .then(() => { + const subscriber = { + next: observer.next.bind(observer), + error: observer.error.bind(observer), + complete: observer.complete.bind(observer) + } + + // Retry last failed request + forward(operation).subscribe(subscriber) + }) + .catch(error => { + // No auth0 access token available, we force user to login + observer.error(error) + }) + }) + } + } + } +) + +const authLink = setContext(async (_, { headers }) => { + // get the authentication token from local storage if it exists + await getItem('access_token').then(token => { + return { + headers: { + ...headers, + Authorization: token ? `Bearer ${token}` : `` + } + } + }) +}) + +const cache = new InMemoryCache().restore(window.__APOLLO_STATE__) + +export const client = new ApolloClient({ + link: ApolloLink.from([authRetryLink, authLink, link]), + cache, + connectToDevTools: true +}) diff --git a/client/src/index.js b/client/src/index.js index 6438fd3e1..e6c15fbd9 100644 --- a/client/src/index.js +++ b/client/src/index.js @@ -2,9 +2,9 @@ import React from 'react' import ReactDOM from 'react-dom' -import App from './App' +import MasterApp from './App' -ReactDOM.render(, document.getElementById('root')) +ReactDOM.render(, document.getElementById('root')) let frontendReloadCount = 0 diff --git a/client/src/styles/index.js b/client/src/styles/index.js new file mode 100644 index 000000000..26043dfc0 --- /dev/null +++ b/client/src/styles/index.js @@ -0,0 +1,72 @@ +import { createMuiTheme } from '@material-ui/core/styles' +import indigo from '@material-ui/core/colors/indigo' +// import red from '@material-ui/core/colors/red' + +export const theme = createMuiTheme({ + palette: { + primary: { main: '#303036' }, + secondary: indigo + }, + 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 diff --git a/client/src/utils/js-helpers.js b/client/src/utils/js-helpers.js new file mode 100644 index 000000000..7db4cb28a --- /dev/null +++ b/client/src/utils/js-helpers.js @@ -0,0 +1,70 @@ +export function isDefined (d) { + return d !== null && typeof d !== 'undefined' +} + +export function isNotDefined (d) { + return !isDefined(d) +} + +export const isArray = Array.isArray + +export function isObject (d) { + return isDefined(d) && typeof d === 'object' && !Array.isArray(d) +} + +export function isEmpty (obj) { + for (var key in obj) { + if (obj.hasOwnProperty(key)) return false + } + return true +} + +export function isString (value) { + return typeof value === 'string' || value instanceof String +} + +export function validObject (object, ...keys) { + return keys.reduce((a, b) => (a || {})[b], object) !== undefined +} + +export function mergeDeep (target, ...sources) { + if (!sources.length) return target + const source = sources.shift() + + if (isObject(target) && isObject(source)) { + for (const key in source) { + if (isObject(source[key])) { + if (!target[key]) Object.assign(target, { [key]: {} }) + mergeDeep(target[key], source[key]) + } else { + Object.assign(target, { [key]: source[key] }) + } + } + } + return mergeDeep(target, ...sources) +} + +export function deleteCookie (c) { + document.cookie.split(';').forEach(function (c) { + document.cookie = c + .replace(/^ +/, '') + .replace(/=.*/, '=;expires=' + new Date().toUTCString() + ';path=/') + }) +} + +export function slugify (string) { + const a = 'àáäâãåèéëêìíïîòóöôùúüûñçßÿœæŕśńṕẃǵǹḿǘẍźḧ·/_,:;' + const b = 'aaaaaaeeeeiiiioooouuuuncsyoarsnpwgnmuxzh------' + const p = new RegExp(a.split('').join('|'), 'g') + + return string + .toString() + .toLowerCase() + .replace(/\s+/g, '-') // Replace spaces with - + .replace(p, c => b.charAt(a.indexOf(c))) // Replace special characters + .replace(/&/g, '-and-') // Replace & with 'and' + .replace(/[^\w-]+/g, '') // Remove all non-word characters + .replace(/--+/g, '-') // Replace multiple - with single - + .replace(/^-+/, '') // Trim - from start of text + .replace(/-+$/, '') // Trim - from end of text +} diff --git a/client/src/utils/local-storage.js b/client/src/utils/local-storage.js new file mode 100644 index 000000000..963ba0f36 --- /dev/null +++ b/client/src/utils/local-storage.js @@ -0,0 +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) + +export { + getItem, + setItem, + removeItem +} diff --git a/client/src/views/callback/index.js b/client/src/views/callback/index.js new file mode 100644 index 000000000..e69de29bb diff --git a/client/src/views/footer/index.js b/client/src/views/footer/index.js new file mode 100644 index 000000000..68bf35d2e --- /dev/null +++ b/client/src/views/footer/index.js @@ -0,0 +1,160 @@ +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/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.propTypes = { + classes: PropTypes.object.isRequired +} + +export default withStyles(styles)(Footer) diff --git a/client/src/views/header/LoggedIn.js b/client/src/views/header/LoggedIn.js new file mode 100644 index 000000000..bc6ef2d07 --- /dev/null +++ b/client/src/views/header/LoggedIn.js @@ -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 ( +
+

+ +

+
+ ) +} + +LoggedIn.propTypes = { + data: PropTypes.object, + user: PropTypes.object.isRequired, + auth: PropTypes.object.isRequired +} + +export default graphql(GetCurrentMember)(LoggedIn) diff --git a/client/src/views/header/LoggedInMenu.js b/client/src/views/header/LoggedInMenu.js new file mode 100644 index 000000000..574a8e0ed --- /dev/null +++ b/client/src/views/header/LoggedInMenu.js @@ -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 => +const LogoutLink = 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 ( + + + + + +
Profile
+
+ + +
Logout
+
+
+
+ ) + } + + 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 diff --git a/client/src/views/header/LoggedOut.js b/client/src/views/header/LoggedOut.js new file mode 100644 index 000000000..e69de29bb diff --git a/client/src/views/header/index.js b/client/src/views/header/index.js new file mode 100644 index 000000000..20a58b20e --- /dev/null +++ b/client/src/views/header/index.js @@ -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/advanced-algos/aa-logo-dark.svg' + +const AboutLink = props => +const TeamsLink = props => +const DashboardLink = props => +const HomeLink = 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 Header 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 ( +
+ + + Advanced Algos + + Teams + + + + + + + + + {this.state.user !== undefined && this.state.user !== null ? ( + + + + + + + ) : ( + + )} + + +
+ ) + } +} + +Header.propTypes = { + classes: PropTypes.object.isRequired, + auth: PropTypes.object.isRequired +} + +export default withStyles(styles)(Header) diff --git a/client/src/views/home/index.js b/client/src/views/home/index.js new file mode 100644 index 000000000..60ee1ecd5 --- /dev/null +++ b/client/src/views/home/index.js @@ -0,0 +1,61 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import CssBaseline from '@material-ui/core/CssBaseline' +import Typography from '@material-ui/core/Typography' +import { withStyles } from '@material-ui/core/styles' + +const styles = theme => ({ + '@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` + } +}) + +const Home = ({ classes }) => ( + + +
+
+ + Collaborate. Innovate. Evolve. + + + Welcome to Advanced Algos + +
+
+
+) + +Home.propTypes = { + classes: PropTypes.object.isRequired +} + +export default withStyles(styles)(Home) diff --git a/client/src/views/index.js b/client/src/views/index.js new file mode 100644 index 000000000..c3cf45256 --- /dev/null +++ b/client/src/views/index.js @@ -0,0 +1,6 @@ +import Header from './header' +import Footer from './footer' +import Home from './home' +import Callback from './callback' + +export { Header, Footer, Home, Callback }