Merge pull request #8 from AdvancedAlgos/develop
Fix Images for Master App and move uploads to dev storage
This commit is contained in:
51 files changed
+2618
-184
No files matched your search
@@ -1,4 +1,5 @@
|
||||
# Advanced Algos Team Module
|
||||
[](https://badge.fury.io/js/%40advancedalgos%2Fteams-client)
|
||||
|
||||
## Introduction
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ const TEAMS_FRAGMENT = gql`{
|
||||
createdAt
|
||||
profile {
|
||||
avatar
|
||||
banner
|
||||
description
|
||||
motto
|
||||
updatedAt
|
||||
|
||||
+6
-11
@@ -162,13 +162,13 @@ const resolvers = {
|
||||
async createTeam(parent, { name, slug, botName, botSlug }, ctx, info) {
|
||||
console.log('createTeam ctx:', ctx.request.user)
|
||||
const authId = ctx.request.user.sub
|
||||
const encodedAuthId = encodeURI(`:"${authId}"`)
|
||||
const encodedURL = `https://users-api.advancedalgos.net/graphql?query=%7B%0A%20%20userByAuthId(authId${encodedAuthId})%7B%0A%20%20%20%20id%0A%09%09email%0A%20%20%20%20alias%0A%20%20%7D%0A%7D`
|
||||
const encodedAuthId = encodeURI(authId)
|
||||
const encodedURL = `https://users-api.advancedalgos.net/graphql?query=%7B%0A%20%20userByAuthId(authId%3A%20"${encodedAuthId}")%7B%0A%20%20%20%20id%0A%09%09email%0A%20%20%20%20alias%0A%20%20%7D%0A%7D`
|
||||
const decodedURL = decodeURI(encodedURL)
|
||||
console.log('decoded URL: ', decodedURL)
|
||||
console.log('createTeam URLs: ', encodedURL, decodedURL)
|
||||
const getUserModuleUser = await axios.get(encodedURL)
|
||||
.then((result) => {
|
||||
console.log('getUserModuleUser:', result)
|
||||
console.log('getUserModuleUser axios:', result)
|
||||
return result
|
||||
})
|
||||
.catch(err =>{
|
||||
@@ -182,8 +182,8 @@ const resolvers = {
|
||||
const banner = 'https://algobotcommstorage.blob.core.windows.net/aateammodule/aa-banner-default.png'
|
||||
|
||||
const createTeamUrl = encodeURI(`${slug}/${name}/${alias}/${botSlug}/${authId}`)
|
||||
// const platformUrl = 'https://develop.advancedalgos.net/AABrowserAPI/teamSetup/'
|
||||
const platformUrl = 'http://localhost:1337/AABrowserAPI/teamSetup/'
|
||||
const platformUrl = 'https://develop.advancedalgos.net/AABrowserAPI/teamSetup/'
|
||||
// const platformUrl = 'http://localhost:3100/AABrowserAPI/teamSetup/'
|
||||
const createPlatformTeam = await axios.get(`${platformUrl}${createTeamUrl}`)
|
||||
.then((result) => {
|
||||
console.log('createPlatformTeam:', result)
|
||||
@@ -232,11 +232,6 @@ const resolvers = {
|
||||
return error.message
|
||||
})
|
||||
})
|
||||
},
|
||||
async getAzureSAS(parent, { teamSlug }, ctx, info) {
|
||||
const SASUrl = createSASQueryURL(teamSlug)
|
||||
console.log('createSASQueryURL: ', SASUrl)
|
||||
return SASUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ type Mutation {
|
||||
updateTeamProfile(slug: String!, description: String, motto: String, avatar: String, banner: String): Team @isAuthenticated
|
||||
updateFB(fbId: String!, avatar: String): FinancialBeings @isAuthenticated
|
||||
deleteTeam(slug: String!): Team @isAuthenticated @isOwner(type: "Team")
|
||||
getAzureSAS(teamSlug: String!):String
|
||||
sendMemberInviteSG(email: String!, teamId: String!): String
|
||||
confirmMember(token: String!): String
|
||||
removeTeamMember(teamId: String!, memberId: String!): String
|
||||
|
||||
Generated
+14
-22
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "@advancedalgos/teams-client",
|
||||
"version": "0.0.20",
|
||||
"version": "0.0.22",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@advancedalgos/web-components": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@advancedalgos/web-components/-/web-components-0.0.10.tgz",
|
||||
"integrity": "sha512-aYmA8HGkh+c2L1LuONfVQA2dHNHtKPctB0IdAOhElJBW4zaETrzQJkq0DHcZzDBGgbnafaX5ydq27Pm617K8Iw==",
|
||||
"version": "0.0.13",
|
||||
"resolved": "https://registry.npmjs.org/@advancedalgos/web-components/-/web-components-0.0.13.tgz",
|
||||
"integrity": "sha512-jXz2w/r08GX8uqB4UTDaow27T3juvR7Bk/80TWmDORVPNCPK152MEUBgxF161hAyOj1jdB+K4M1Fy5GkEpDhmw==",
|
||||
"requires": {
|
||||
"@azure/storage-blob": "^10.1.0-preview",
|
||||
"@material-ui/core": "^3.0.3",
|
||||
"@material-ui/core": "^3.2.2",
|
||||
"@material-ui/icons": "^3.0.1",
|
||||
"apollo-client": "^2.4.2",
|
||||
"blob-util": "^2.0.2",
|
||||
@@ -44,14 +44,6 @@
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz",
|
||||
"integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA=="
|
||||
},
|
||||
"graphql": {
|
||||
"version": "14.0.2",
|
||||
"resolved": "https://registry.npmjs.org/graphql/-/graphql-14.0.2.tgz",
|
||||
"integrity": "sha512-gUC4YYsaiSJT1h40krG3J+USGlwhzNTXSb4IOZljn9ag5Tj+RkoXrWp+Kh7WyE3t1NCfab5kzCuxBIvOMERMXw==",
|
||||
"requires": {
|
||||
"iterall": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"ms-rest-js": {
|
||||
"version": "0.22.425",
|
||||
"resolved": "https://registry.npmjs.org/ms-rest-js/-/ms-rest-js-0.22.425.tgz",
|
||||
@@ -2001,9 +1993,9 @@
|
||||
}
|
||||
},
|
||||
"@material-ui/core": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-3.2.0.tgz",
|
||||
"integrity": "sha512-fThWolLWQoUMV8exLxe9NqfegFFHmV8T7kJBvk3iX47c7TrAw4Vgyvft4CApnQoYIZbrRfPMig5ovYDvmTmMCg==",
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-3.2.2.tgz",
|
||||
"integrity": "sha512-wDTJyR76+OBdlltiPs3lc1gD6zR+dSA6nITtgkBeLf1NvWfNotMWdvldIDnF3bu24ySAX9imfzDfkBu4Edtqww==",
|
||||
"requires": {
|
||||
"@babel/runtime": "7.1.2",
|
||||
"@types/jss": "^9.5.6",
|
||||
@@ -2198,9 +2190,9 @@
|
||||
}
|
||||
},
|
||||
"@types/jss": {
|
||||
"version": "9.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/jss/-/jss-9.5.6.tgz",
|
||||
"integrity": "sha512-7TWmR5y1jYG4ka4wTZt65RR0kw4WgALFUWktQIWbLnDd6/z/0SQZ/4+UeH0rhdp+HEdIfmzPBH0VwE/4Z9Evzw==",
|
||||
"version": "9.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/jss/-/jss-9.5.7.tgz",
|
||||
"integrity": "sha512-OZimStu2QdDMtZ0h72JXqvLVbWUjXd5ZLk8vxLmfuC/nM1AabRyyGoxSufnzixrbpEcVcyy/JV5qeQu2JnjVZw==",
|
||||
"requires": {
|
||||
"csstype": "^2.0.0",
|
||||
"indefinite-observable": "^1.0.1"
|
||||
@@ -2227,9 +2219,9 @@
|
||||
"integrity": "sha512-HtKGu+qG1NPvYe1z7ezLsyIaXYyi8SoAVqWDZgDQ8dLrsZvSzUNCwZyfX33uhWxL/SU0ZDQZ3nwZ0nimt507Kw=="
|
||||
},
|
||||
"@types/react": {
|
||||
"version": "16.4.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.4.16.tgz",
|
||||
"integrity": "sha512-lxyoipLWweAnLnSsV4Ho2NAZTKKmxeYgkTQ6PaDiPDU9JJBUY2zJVVGiK1smzYv8+ZgbqEmcm5xM74GCpunSEA==",
|
||||
"version": "16.4.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.4.18.tgz",
|
||||
"integrity": "sha512-eFzJKEg6pdeaukVLVZ8Xb79CTl/ysX+ExmOfAAqcFlCCK5TgFDD9kWR0S18sglQ3EmM8U+80enjUqbfnUyqpdA==",
|
||||
"requires": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^2.2.0"
|
||||
|
||||
+6
-4
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@advancedalgos/teams-client",
|
||||
"version": "0.0.20",
|
||||
"version": "0.0.22",
|
||||
"description": "Advanced Algos Team client-side web app",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
@@ -69,10 +69,8 @@
|
||||
"workbox-cli": "^3.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@advancedalgos/web-components": "0.0.10",
|
||||
"@advancedalgos/web-components": "0.0.13",
|
||||
"@azure/storage-blob": "^10.0.0-preview",
|
||||
"@material-ui/core": "^3.2.0",
|
||||
"@material-ui/icons": "^3.0.1",
|
||||
"apollo-cache-inmemory": "^1.3.5",
|
||||
"apollo-client": "^2.4.2",
|
||||
"apollo-link": "^1.2.3",
|
||||
@@ -99,6 +97,10 @@
|
||||
"recompose": "^0.30.0",
|
||||
"subscriptions-transport-ws": "^0.9.15"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@material-ui/core": "^3.2.0",
|
||||
"@material-ui/icons": "^3.0.1"
|
||||
},
|
||||
"standard": {
|
||||
"parser": "babel-eslint",
|
||||
"ignore": [
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const AddAlgobotMutation = gql`
|
||||
mutation addAlgobot($input: AddAlgobotInput!) {
|
||||
addAlgobot(input: $input) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
owner
|
||||
avatar
|
||||
repo
|
||||
team_id
|
||||
type
|
||||
}
|
||||
}
|
||||
`
|
||||
@@ -1,10 +0,0 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const DeleteAlgobotMutation = gql`
|
||||
mutation deleteAlgobot($id: Int!) {
|
||||
deleteAlgobot(id: $id) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
@@ -1,19 +0,0 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const GetAlgobotQuery = gql`
|
||||
query getAlgobotByOwner($owner: Int!) {
|
||||
getAlgobotByOwner(owner: $owner) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
owner
|
||||
avatar
|
||||
repo
|
||||
team_id
|
||||
type
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export default GetAlgobotQuery
|
||||
@@ -1,29 +0,0 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const GetAllAlgobotsQuery = gql`
|
||||
query algobots($limit: Int!, $after: Int) {
|
||||
algobots(limit: $limit, after: $after) {
|
||||
totalCount
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
id
|
||||
name
|
||||
slug
|
||||
owner
|
||||
avatar
|
||||
repo
|
||||
team_id
|
||||
type
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
endCursor
|
||||
hasNextPage
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export default GetAllAlgobotsQuery
|
||||
@@ -1,10 +0,0 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const UniqueAlgobotnameQuery = gql`
|
||||
query uniqueAlgobotname($algobotname: String!) {
|
||||
uniqueAlgobotname(algobotname: $algobotname)
|
||||
}
|
||||
`
|
||||
|
||||
export default UniqueAlgobotnameQuery
|
||||
@@ -3,7 +3,7 @@ import gql from 'graphql-tag'
|
||||
|
||||
export const GetCurrentMember = gql`
|
||||
query currentMember {
|
||||
currentMember {
|
||||
teams_CurrentMember {
|
||||
...MemberInfo
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const USER_BY_AUTHID = gql`
|
||||
query($authId: String){
|
||||
userByAuthId (authId: $authId){
|
||||
id
|
||||
alias
|
||||
firstName
|
||||
middleName
|
||||
lastName
|
||||
bio
|
||||
email
|
||||
emailVerified
|
||||
isDeveloper
|
||||
isDataAnalyst
|
||||
isTrader
|
||||
role {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export default USER_BY_AUTHID
|
||||
@@ -1,4 +1,3 @@
|
||||
import { GetCurrentMember } from './GetCurrentMemberQuery'
|
||||
import { USER_BY_AUTHID } from './GetUserByAuthIDQuery'
|
||||
|
||||
export { GetCurrentMember, USER_BY_AUTHID }
|
||||
export { GetCurrentMember }
|
||||
@@ -3,7 +3,7 @@ import gql from 'graphql-tag'
|
||||
|
||||
const CREATE_TEAM = gql`
|
||||
mutation CreateTeamMutation($name: String!, $slug: String!, $botName: String!, $botSlug: String!) {
|
||||
createTeam(name: $name, slug: $slug, botName: $botName, botSlug: $botSlug) {
|
||||
teams_CreateTeam(name: $name, slug: $slug, botName: $botName, botSlug: $botSlug) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
|
||||
@@ -3,7 +3,7 @@ import gql from 'graphql-tag'
|
||||
|
||||
export const DELETE_TEAM = gql`
|
||||
mutation deleteTeam($slug: String!) {
|
||||
deleteTeam(slug: $slug) {
|
||||
teams_DeleteTeam(slug: $slug) {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const GET_AZURE_SAS = gql`
|
||||
mutation getAzureSAS($teamSlug: String!) {
|
||||
getAzureSAS(teamSlug: $teamSlug)
|
||||
}
|
||||
`
|
||||
|
||||
export default GET_AZURE_SAS
|
||||
@@ -3,7 +3,7 @@ import gql from 'graphql-tag'
|
||||
|
||||
export const GET_TEAMS_BY_OWNER = gql`
|
||||
query teamsByOwnerQuery($authId: String!) {
|
||||
teamsByOwner(ownerId: $authId) {
|
||||
teams_TeamsByOwner(ownerId: $authId) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
|
||||
@@ -3,7 +3,7 @@ import gql from 'graphql-tag'
|
||||
|
||||
export const REMOVE_TEAM_MEMBER = gql`
|
||||
mutation removeTeamMember($teamId: String!, $memberId: String!) {
|
||||
removeTeamMember(teamId: $teamId, memberId: $memberId) {
|
||||
teams_RemoveTeamMember(teamId: $teamId, memberId: $memberId) {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import gql from 'graphql-tag'
|
||||
|
||||
export const SEND_MEMBER_INVITE = gql`
|
||||
mutation sendMemberInvite($email: String!, $teamId: String!) {
|
||||
sendMemberInviteSG(email: $email, teamId: $teamId)
|
||||
teams_SendMemberInviteSG(email: $email, teamId: $teamId)
|
||||
}
|
||||
`
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import gql from 'graphql-tag'
|
||||
|
||||
export const SET_TEAM_MEMBER_ROLE = gql`
|
||||
mutation setTeamMemberRole($teamId: String!, $memberId: String!, $role: String!) {
|
||||
setTeamMemberRole(teamId: $teamId, memberId: $memberId, role: $role) {
|
||||
teams_SetTeamMemberRole(teamId: $teamId, memberId: $memberId, role: $role) {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import gql from 'graphql-tag'
|
||||
|
||||
export const UniqueTeamnameQuery = gql`
|
||||
query uniqueTeamname($name: String!) {
|
||||
teamByName(name: $name) {
|
||||
teams_TeamByName(name: $name) {
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import gql from 'graphql-tag'
|
||||
|
||||
const UPDATE_FB = gql`
|
||||
mutation UpdateFBMutation($fbId: String!, $avatar: String) {
|
||||
updateFB(fbId: $fbId, avatar: $avatar) {
|
||||
teams_UpdateFB(fbId: $fbId, avatar: $avatar) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
|
||||
@@ -9,7 +9,7 @@ const UPDATE_TEAM_PROFILE = gql`
|
||||
$avatar: String,
|
||||
$banner: String
|
||||
) {
|
||||
updateTeamProfile(
|
||||
teams_UpdateTeamProfile(
|
||||
slug: $slug,
|
||||
description: $description,
|
||||
motto: $motto
|
||||
|
||||
+52
-7
@@ -6,29 +6,74 @@ import { hot } from 'react-hot-loader'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import {
|
||||
AcceptTeamInvite,
|
||||
Dashboard,
|
||||
ManageTeams,
|
||||
TeamMembers,
|
||||
FinancialBeings,
|
||||
Settings,
|
||||
Teams,
|
||||
TeamBar,
|
||||
globalStyles
|
||||
} from './views'
|
||||
|
||||
import { getItem } from './utils/local-storage'
|
||||
|
||||
class App extends Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
user: null
|
||||
}
|
||||
}
|
||||
|
||||
async componentDidMount () {
|
||||
let user = await getItem('user')
|
||||
|
||||
if (user !== null && user !== undefined && user !== 'undefined') {
|
||||
user = JSON.parse(user)
|
||||
this.setState({ user: user })
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { match } = this.props
|
||||
let loggedIn
|
||||
if (this.state.user !== null) {
|
||||
loggedIn = (<TeamBar match={match} user={this.state.user} />)
|
||||
} else {
|
||||
loggedIn = ''
|
||||
}
|
||||
return (
|
||||
<BrowserRouter basename={window.location.pathname}>
|
||||
<BrowserRouter>
|
||||
<div className='App'>
|
||||
{loggedIn}
|
||||
<Switch>
|
||||
<Route exact path='/' component={Teams} />
|
||||
<Route exact path='/:slug' component={Teams} />
|
||||
<Route exact path={`${match.path}`} component={Teams} />
|
||||
<Route
|
||||
exact
|
||||
path='/(dashboard|manage-teams|team-members|financial-beings|settings)/'
|
||||
render={props => <Dashboard {...props} auth={this.props.auth} />}
|
||||
path={`${match.path}/manage-teams`}
|
||||
render={props => <ManageTeams {...props} auth={this.props.auth} />}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path='/activate-team-membership'
|
||||
path={`${match.path}/team-members`}
|
||||
render={props => <TeamMembers {...props} auth={this.props.auth} />}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path={`${match.path}/financial-beings`}
|
||||
render={props => <FinancialBeings {...props} auth={this.props.auth} />}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path={`${match.path}/financial-beings`}
|
||||
render={props => <Settings {...props} auth={this.props.auth} />}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path={`${match.path}/activate-team-membership`}
|
||||
render={props => <AcceptTeamInvite {...props} auth={this.props.auth} />}
|
||||
/>
|
||||
<Route path='/teams/:slug' component={Teams} />
|
||||
</Switch>
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import classNames from 'classnames'
|
||||
import AppBar from '@material-ui/core/AppBar'
|
||||
import Toolbar from '@material-ui/core/Toolbar'
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
import Button from '@material-ui/core/Button'
|
||||
|
||||
// icons
|
||||
import GroupIcon from '@material-ui/icons/Group'
|
||||
import UsersIcon from '@material-ui/icons/People'
|
||||
import SearchIcon from '@material-ui/icons/Search'
|
||||
import AdbIcon from '@material-ui/icons/Adb'
|
||||
import SettingsApplicationsIcon from '@material-ui/icons/SettingsApplications'
|
||||
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
const SettingsLink = props => <Link to='/teams/settings' {...props} />
|
||||
const FBLink = props => <Link to='/teams/financial-beings' {...props} />
|
||||
const MembersLink = props => <Link to='/teams/team-members' {...props} />
|
||||
const ManageLink = props => <Link {...props} />
|
||||
const ViewLink = props => <Link to='/teams' {...props} />
|
||||
|
||||
const styles = theme => ({
|
||||
root: {
|
||||
flexGrow: 1
|
||||
},
|
||||
flex: {
|
||||
flexGrow: 1,
|
||||
marginLeft: 30
|
||||
},
|
||||
menuButton: {
|
||||
marginLeft: -12,
|
||||
marginRight: 20
|
||||
},
|
||||
cssRoot: {
|
||||
color: '#FFFFFF',
|
||||
backgroundColor: theme.palette.secondary,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.dark
|
||||
},
|
||||
whiteSpace: 'nowrap',
|
||||
paddingRight: 2 * theme.spacing.unit,
|
||||
paddingLeft: 2 * theme.spacing.unit
|
||||
},
|
||||
button: {
|
||||
margin: theme.spacing.unit
|
||||
},
|
||||
leftIcon: {
|
||||
marginRight: theme.spacing.unit
|
||||
},
|
||||
rightIcon: {
|
||||
marginLeft: theme.spacing.unit
|
||||
},
|
||||
iconSmall: {
|
||||
fontSize: 20
|
||||
}
|
||||
})
|
||||
|
||||
class TeamBar extends Component {
|
||||
render () {
|
||||
const { classes, user, match } = this.props
|
||||
console.log('TeamBar: ', user, match)
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<AppBar position='static' color='secondary'>
|
||||
<Toolbar>
|
||||
<Typography variant='h5' color='inherit' className={classes.flex}>
|
||||
Manage Teams
|
||||
</Typography>
|
||||
<Button
|
||||
variant='text'
|
||||
size='small'
|
||||
className={classNames(classes.button, classes.cssRoot)}
|
||||
title='View all teams'
|
||||
component={ViewLink}
|
||||
to={`${match.url}`}>
|
||||
<SearchIcon className={classNames(classes.leftIcon, classes.iconSmall)} />
|
||||
All Teams
|
||||
</Button>
|
||||
<Button
|
||||
variant='text'
|
||||
size='small'
|
||||
className={classNames(classes.button, classes.cssRoot)}
|
||||
title='Manage your teams'
|
||||
component={ManageLink}
|
||||
to={`${match.url}/manage-teams`}>
|
||||
<GroupIcon className={classNames(classes.leftIcon, classes.iconSmall)} />
|
||||
Your Teams
|
||||
</Button>
|
||||
<Button
|
||||
variant='text'
|
||||
size='small'
|
||||
className={classNames(classes.button, classes.cssRoot)}
|
||||
title='Manage team members'
|
||||
component={MembersLink}
|
||||
to={`${match.url}/team-members`}>
|
||||
<UsersIcon className={classNames(classes.leftIcon, classes.iconSmall)} />
|
||||
Team Members
|
||||
</Button>
|
||||
<Button
|
||||
variant='text'
|
||||
size='small'
|
||||
className={classNames(classes.button, classes.cssRoot)}
|
||||
title='Manage Financial Beings'
|
||||
component={FBLink}
|
||||
to={`${match.url}/financial-beings`}>
|
||||
<AdbIcon className={classNames(classes.leftIcon, classes.iconSmall)} />
|
||||
Financial Beings
|
||||
</Button>
|
||||
<Button
|
||||
variant='text'
|
||||
size='small'
|
||||
className={classNames(classes.button, classes.cssRoot)}
|
||||
title='Manage Financial Beings'
|
||||
component={SettingsLink}
|
||||
to={`${match.url}/settings`}>
|
||||
<SettingsApplicationsIcon className={classNames(classes.leftIcon, classes.iconSmall)} />
|
||||
Settings
|
||||
</Button>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
TeamBar.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
user: PropTypes.object,
|
||||
match: PropTypes.object
|
||||
}
|
||||
|
||||
export default withStyles(styles)(TeamBar)
|
||||
@@ -0,0 +1,3 @@
|
||||
import TeamBar from './components/TeamBar'
|
||||
|
||||
export { TeamBar }
|
||||
@@ -0,0 +1,204 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Mutation } from 'react-apollo'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
|
||||
import Button from '@material-ui/core/Button'
|
||||
import EditIcon from '@material-ui/icons/Edit'
|
||||
import TextField from '@material-ui/core/TextField'
|
||||
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 Typography from '@material-ui/core/Typography'
|
||||
|
||||
import { ImageUpload } from '@advancedalgos/web-components'
|
||||
|
||||
import UPDATE_FB from '../../../graphql/teams/UpdateFBMutation'
|
||||
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
|
||||
|
||||
import { checkGraphQLError } from '../../../utils/graphql-errors'
|
||||
|
||||
const styles = theme => ({
|
||||
dialogContainer: {
|
||||
display: 'block',
|
||||
margin: '3em',
|
||||
minWidth: 400
|
||||
},
|
||||
buttonRight: {
|
||||
justifyContent: 'flex-end'
|
||||
}
|
||||
})
|
||||
|
||||
export class ManageFBEdit extends Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.handleClickOpen = this.handleClickOpen.bind(this)
|
||||
this.handleClose = this.handleClose.bind(this)
|
||||
this.handleSubmit = this.handleSubmit.bind(this)
|
||||
this.handleAvatar = this.handleAvatar.bind(this)
|
||||
|
||||
const avatar = props.fb.avatar || ''
|
||||
this.authId = props.authId
|
||||
|
||||
this.state = {
|
||||
open: false,
|
||||
avatar: avatar
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
console.log('ManageFBEdit ', this.props, this.props.slug, this.props.fb)
|
||||
const { classes, fb, slug } = this.props
|
||||
return (
|
||||
<Mutation
|
||||
mutation={UPDATE_FB}
|
||||
refetchQueries={[
|
||||
{
|
||||
query: GET_TEAMS_BY_OWNER,
|
||||
variables: { authId: this.authId }
|
||||
}
|
||||
]}
|
||||
>
|
||||
{(updateFB, { loading, error, data }) => {
|
||||
const AzureStorageUrl = process.env.AZURE_STORAGE_URL_TEAMS
|
||||
const AzureStorageSAS = process.env.AZURE_STORAGE_SAS_TEAMS
|
||||
const containerName = slug
|
||||
|
||||
let avatar = null
|
||||
if (this.state.avatar === null && fb.avatar === undefined) avatar = 'https://algobotcommstorage.blob.core.windows.net/aateammodule/aa-avatar-default.png'
|
||||
if (fb.avatar !== undefined && fb.avatar !== null) avatar = fb.avatar
|
||||
if (this.state.avatar !== null) avatar = this.state.avatar
|
||||
|
||||
let errors
|
||||
let loader
|
||||
if (loading) {
|
||||
loader = (
|
||||
<Typography variant='caption'>Submitting team...</Typography>
|
||||
)
|
||||
}
|
||||
if (error) {
|
||||
errors = error.graphQLErrors.map(({ message }, i) => {
|
||||
const displayMessage = checkGraphQLError(message)
|
||||
console.log('updateTeamProfile error:', displayMessage)
|
||||
return (
|
||||
<Typography key={i} variant='caption'>
|
||||
{message}
|
||||
</Typography>
|
||||
)
|
||||
})
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
size='small'
|
||||
color='primary'
|
||||
className={classes.buttonRight}
|
||||
onClick={this.handleClickOpen}
|
||||
>
|
||||
<EditIcon /> Edit
|
||||
</Button>
|
||||
<Dialog
|
||||
open={this.state.open}
|
||||
onClose={this.handleClose}
|
||||
aria-labelledby='form-dialog-title'
|
||||
>
|
||||
<div classes={classes.dialogContainer}>
|
||||
<DialogTitle id='form-dialog-title'>
|
||||
Edit Financial Being
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>Update Financial Beings's Avatar</DialogContentText>
|
||||
<ImageUpload
|
||||
key='avatar'
|
||||
handleUrl={this.handleAvatar}
|
||||
fileName={`${fb.slug}-fb-avatar.jpg`}
|
||||
containerName={containerName}
|
||||
existingImage={avatar}
|
||||
imagePreviewConfig={{ width: 200, title: 'Change FB Avatar' }}
|
||||
cropContainerConfig={{ x: 10, y: 10, width: 200, height: 200 }}
|
||||
cropPreviewBox={{ width: 350, height: 350 }}
|
||||
saveImageConfig={{
|
||||
quality: 0.6,
|
||||
maxWidth: 200,
|
||||
maxHeight: 200,
|
||||
autoRotate: true,
|
||||
mimeType: 'image/jpeg'
|
||||
}}
|
||||
AzureStorageUrl={AzureStorageUrl}
|
||||
AzureSASURL={AzureStorageSAS}
|
||||
cropRatio={1}
|
||||
debug
|
||||
/>
|
||||
<TextField
|
||||
autoFocus
|
||||
margin='dense'
|
||||
id='name'
|
||||
label='Team Name'
|
||||
type='text'
|
||||
fullWidth
|
||||
disabled
|
||||
value={fb.name}
|
||||
/>
|
||||
{loader}
|
||||
{errors}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color='primary'>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={e => {
|
||||
this.handleSubmit(e, updateFB, fb.id, slug)
|
||||
}}
|
||||
color='primary'
|
||||
>
|
||||
Update Financial Being
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</Mutation>
|
||||
)
|
||||
}
|
||||
|
||||
handleClickOpen () {
|
||||
this.setState({ open: true })
|
||||
}
|
||||
|
||||
handleClose () {
|
||||
this.setState({ open: false })
|
||||
}
|
||||
|
||||
handleAvatar (avatarUrl) {
|
||||
console.log('handleAvatar: ', avatarUrl)
|
||||
this.setState({ avatar: `${avatarUrl}?${Math.random()}` })
|
||||
}
|
||||
|
||||
async handleSubmit (e, updateFB, fbId, slug) {
|
||||
console.log('handleSubmit: ', this.state)
|
||||
e.preventDefault()
|
||||
|
||||
await updateFB({
|
||||
variables: {
|
||||
fbId,
|
||||
avatar: this.state.avatar
|
||||
}
|
||||
})
|
||||
this.setState({ open: false })
|
||||
}
|
||||
}
|
||||
|
||||
ManageFBEdit.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
slug: PropTypes.string.isRequired,
|
||||
fb: PropTypes.object,
|
||||
authId: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default withStyles(styles)(ManageFBEdit)
|
||||
@@ -0,0 +1,53 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import Grid from '@material-ui/core/Grid'
|
||||
import Card from '@material-ui/core/Card'
|
||||
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 ManageFBEdit from './ManageFBEdit'
|
||||
|
||||
export const ManageFBItem = ({ classes, team, authId }) => {
|
||||
console.log('ManageFBItem', team, team.fb[0], team.profile.avatar)
|
||||
let avatar
|
||||
if (team.fb[0].avatar !== undefined && team.fb[0].avatar !== 'a') {
|
||||
avatar = team.fb[0].avatar
|
||||
} else {
|
||||
avatar = 'https://algobotcommstorage.blob.core.windows.net/aateammodule/aa-avatar-default.png'
|
||||
}
|
||||
return (
|
||||
<Grid item xs={12}>
|
||||
<Card className={classes.card}>
|
||||
<div className={classes.cardDetails}>
|
||||
<CardMedia
|
||||
className={classes.cardMedia}
|
||||
image={avatar}
|
||||
title={team.name}
|
||||
/>
|
||||
<CardContent className={classes.cardContent}>
|
||||
<Typography gutterBottom variant='h5' component='h2'>
|
||||
{team.fb[0].name}
|
||||
</Typography>
|
||||
<Typography variant='caption' color='textSecondary'>
|
||||
{team.fb[0].kind}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
<CardActions>
|
||||
<ManageFBEdit slug={team.slug} fb={team.fb[0]} authId={authId} />
|
||||
</CardActions>
|
||||
</div>
|
||||
</Card>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
|
||||
ManageFBItem.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
team: PropTypes.object.isRequired,
|
||||
authId: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default ManageFBItem
|
||||
@@ -0,0 +1,139 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Query } from 'react-apollo'
|
||||
import { withStateHandlers, lifecycle, compose } from 'recompose'
|
||||
|
||||
import Grid from '@material-ui/core/Grid'
|
||||
import { MessageCard } from '@advancedalgos/web-components'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
|
||||
import { isDefined, isString } from '../../../utils/js-helpers'
|
||||
import { getItem } from '../../../utils/local-storage'
|
||||
|
||||
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
|
||||
|
||||
import ManageFBItem from './ManageFBItem'
|
||||
|
||||
const styles = theme => ({
|
||||
heroContent: {
|
||||
maxWidth: 600,
|
||||
margin: '0 auto',
|
||||
padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px`
|
||||
},
|
||||
cardGrid: {
|
||||
padding: `${theme.spacing.unit * 8}px 0`
|
||||
},
|
||||
buttonRight: {
|
||||
justifyContent: 'flex-end'
|
||||
},
|
||||
card: {
|
||||
display: 'flex',
|
||||
width: '100%'
|
||||
},
|
||||
cardDetails: {
|
||||
display: 'flex',
|
||||
flex: 1
|
||||
},
|
||||
cardContent: {
|
||||
flex: 1
|
||||
},
|
||||
cardMedia: {
|
||||
flex: 1,
|
||||
width: 100,
|
||||
height: 100,
|
||||
maxWidth: 100,
|
||||
justifyContent: 'flex-start'
|
||||
}
|
||||
})
|
||||
|
||||
export const ManageFBList = ({ classes, user = null }) => {
|
||||
let owner
|
||||
let authId = null
|
||||
console.log('ManageTeamsList: ', user)
|
||||
if (user !== null && isString(user)) {
|
||||
owner = JSON.parse(user)
|
||||
if (isDefined(owner.authId)) authId = owner.authId
|
||||
}
|
||||
console.log('ManageTeamsList 2: ', owner, authId)
|
||||
if (authId === undefined || authId === null) {
|
||||
return (
|
||||
<Grid container spacing={40}>
|
||||
<Grid>
|
||||
<MessageCard message='Loading...' />
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Query
|
||||
query={GET_TEAMS_BY_OWNER}
|
||||
variables={{ authId }}
|
||||
fetchPolicy='network-only'
|
||||
>
|
||||
{({ loading, error, data }) => {
|
||||
console.log('GET_TEAMS_BY_OWNER: ', loading, error, data)
|
||||
|
||||
let errors = null
|
||||
if (error) {
|
||||
errors = error.graphQLErrors.map(({ message }, i) => {
|
||||
return <MessageCard message={message} />
|
||||
})
|
||||
}
|
||||
if (!loading && !error) {
|
||||
if (data.teams_TeamsByOwner.length > 0) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Grid container spacing={40}>
|
||||
{!loading &&
|
||||
data.teams_TeamsByOwner.map(team => (
|
||||
<ManageFBItem
|
||||
key={team.id}
|
||||
team={team}
|
||||
classes={classes}
|
||||
authId={authId}
|
||||
/>
|
||||
))}
|
||||
{errors}
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<Grid container spacing={40}>
|
||||
<Grid item xs={12}>
|
||||
<MessageCard message='Loading...' />
|
||||
{errors !== null && <MessageCard message={errors} />}
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
}}
|
||||
</Query>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ManageFBList.propTypes = {
|
||||
user: PropTypes.any,
|
||||
classes: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
const getUserOnMount = lifecycle({
|
||||
componentDidMount () {
|
||||
getItem('user').then(user => {
|
||||
this.setState({ user })
|
||||
}) // Set user to state
|
||||
}
|
||||
})
|
||||
|
||||
const mapStateToProps = withStateHandlers(() => ({ user: null }), {
|
||||
user: ({ user }) => () => ({ user })
|
||||
})
|
||||
|
||||
const ManageFBListAuthId = compose(
|
||||
mapStateToProps,
|
||||
getUserOnMount
|
||||
)(ManageFBList)
|
||||
|
||||
export default withStyles(styles)(ManageFBListAuthId)
|
||||
@@ -0,0 +1,28 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
|
||||
import ManageFBList from './components/ManageFBList'
|
||||
|
||||
const styles = theme => ({
|
||||
tableContainer: {
|
||||
height: 320
|
||||
}
|
||||
})
|
||||
|
||||
const FinancialBeings = ({ classes }) => (
|
||||
<div>
|
||||
<Typography variant='h4' gutterBottom>
|
||||
Financial Beings
|
||||
</Typography>
|
||||
<ManageFBList />
|
||||
</div>
|
||||
)
|
||||
|
||||
FinancialBeings.propTypes = {
|
||||
classes: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
export default withStyles(styles)(FinancialBeings)
|
||||
@@ -1,13 +1,22 @@
|
||||
import Dashboard from './dashboard'
|
||||
import ManageTeams from './manage-teams'
|
||||
import TeamMembers from './team-members'
|
||||
import FinancialBeings from './financial-beings'
|
||||
import Settings from './settings'
|
||||
import Teams from './teams'
|
||||
import AcceptTeamInvite from './teams/AcceptTeamInvite'
|
||||
|
||||
import { TeamBar } from './common'
|
||||
|
||||
import { theme, globalStyles } from './theme'
|
||||
|
||||
export {
|
||||
AcceptTeamInvite,
|
||||
Dashboard,
|
||||
ManageTeams,
|
||||
TeamMembers,
|
||||
FinancialBeings,
|
||||
Settings,
|
||||
Teams,
|
||||
TeamBar,
|
||||
theme,
|
||||
globalStyles
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Mutation } from 'react-apollo'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
|
||||
import Button from '@material-ui/core/Button'
|
||||
import AddIcon from '@material-ui/icons/Add'
|
||||
import TextField from '@material-ui/core/TextField'
|
||||
import FormControl from '@material-ui/core/FormControl'
|
||||
import FormHelperText from '@material-ui/core/FormHelperText'
|
||||
import Dialog from '@material-ui/core/Dialog'
|
||||
import DialogActions from '@material-ui/core/DialogActions'
|
||||
import DialogContent from '@material-ui/core/DialogContent'
|
||||
import DialogTitle from '@material-ui/core/DialogTitle'
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
import { isEmpty } from '../../../utils/js-helpers'
|
||||
|
||||
import CREATE_TEAM from '../../../graphql/teams/CreateTeamMutation'
|
||||
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
|
||||
|
||||
// import { checkGraphQLError } from '../../../utils/graphql-errors'
|
||||
|
||||
const styles = theme => ({
|
||||
dialogContainer: {
|
||||
display: 'block',
|
||||
margin: '3em',
|
||||
minWidth: 400
|
||||
},
|
||||
dialogStyle: {
|
||||
padding: '3em'
|
||||
},
|
||||
textField: {
|
||||
width: '60%',
|
||||
marginLeft: '20%',
|
||||
marginBottom: 10
|
||||
},
|
||||
buttonRight: {
|
||||
// position: 'absolute',
|
||||
// right: '3em'
|
||||
marginTop: '1em',
|
||||
marginRight: 'auto',
|
||||
marginLeft: 'auto',
|
||||
display: 'block',
|
||||
lineHeight: '1em'
|
||||
}
|
||||
})
|
||||
|
||||
export class CreateTeamDialog extends Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.handleClickOpen = this.handleClickOpen.bind(this)
|
||||
this.handleClose = this.handleClose.bind(this)
|
||||
this.handleChange = this.handleChange.bind(this)
|
||||
this.handleSubmit = this.handleSubmit.bind(this)
|
||||
this.validate = this.validate.bind(this)
|
||||
this.slugify = this.slugify.bind(this)
|
||||
|
||||
this.state = {
|
||||
open: false,
|
||||
name: '',
|
||||
botName: '',
|
||||
nameError: '',
|
||||
botNameError: ''
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { classes, authId } = this.props
|
||||
return (
|
||||
<Mutation
|
||||
mutation={CREATE_TEAM}
|
||||
refetchQueries={[{
|
||||
query: GET_TEAMS_BY_OWNER,
|
||||
variables: { authId: authId }
|
||||
}]}
|
||||
>
|
||||
{(createTeam, { loading, error, data }) => {
|
||||
let errors
|
||||
let loader = null
|
||||
if (loading) {
|
||||
loader = (
|
||||
<Typography variant='subtitle1'>Submitting team...</Typography>
|
||||
)
|
||||
}
|
||||
if (error) {
|
||||
errors = error.graphQLErrors.map(({ message }, i) => {
|
||||
// const displayMessage = checkGraphQLError(message)
|
||||
return (
|
||||
<Typography key={i} variant='caption'>
|
||||
{message}
|
||||
</Typography>
|
||||
)
|
||||
})
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
variant='fab'
|
||||
color='primary'
|
||||
aria-label='Add'
|
||||
className={classes.buttonRight}
|
||||
onClick={this.handleClickOpen}
|
||||
>
|
||||
<AddIcon />
|
||||
</Button>
|
||||
<Dialog
|
||||
open={this.state.open}
|
||||
onClose={this.handleClose}
|
||||
aria-labelledby='form-dialog-title'
|
||||
>
|
||||
<div classes={classes.dialogContainer}>
|
||||
<DialogTitle id='form-dialog-title'>Create a Team</DialogTitle>
|
||||
<DialogContent>
|
||||
<FormControl
|
||||
required
|
||||
error={this.state.nameError !== '' || this.state.botNameError !== '' || error !== null}
|
||||
>
|
||||
<Typography variant='subtitle1' align='center'>Create a name for your team</Typography>
|
||||
<TextField
|
||||
autoFocus
|
||||
margin='dense'
|
||||
id='name'
|
||||
label='Team Name'
|
||||
type='text'
|
||||
fullWidth
|
||||
className={classes.textField}
|
||||
value={this.state.name}
|
||||
onChange={this.handleChange}
|
||||
error={this.state.nameError !== ''}
|
||||
/>
|
||||
{this.state.nameError !== '' && (
|
||||
<FormHelperText>{this.state.nameError}</FormHelperText>
|
||||
)}
|
||||
<Typography variant='subtitle1' align='center' ><br />
|
||||
Create a name for your teams bot.
|
||||
</Typography>
|
||||
<Typography align='center' >
|
||||
<em>(Temporary: In the future, creating multiple Financial Beings <br />
|
||||
will occur in a separate module)</em>
|
||||
</Typography>
|
||||
<TextField
|
||||
autoFocus
|
||||
margin='dense'
|
||||
id='botName'
|
||||
label='Team Bot Name'
|
||||
type='text'
|
||||
fullWidth
|
||||
className={classes.textField}
|
||||
value={this.state.botName}
|
||||
onChange={this.handleChange}
|
||||
error={this.state.botNameError !== ''}
|
||||
/>
|
||||
{this.state.botNameError !== '' && (
|
||||
<FormHelperText>{this.state.botNameError}</FormHelperText>
|
||||
)}
|
||||
{error && <FormHelperText>{errors}</FormHelperText>}
|
||||
{loader}
|
||||
</FormControl>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color='primary'>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={e => {
|
||||
this.handleSubmit(e, createTeam, this.state.name, this.state.botName)
|
||||
}}
|
||||
color='primary'
|
||||
>
|
||||
Create Team
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</Mutation>
|
||||
)
|
||||
}
|
||||
|
||||
handleClickOpen () {
|
||||
this.setState({ open: true })
|
||||
}
|
||||
|
||||
handleClose () {
|
||||
this.setState({ open: false })
|
||||
}
|
||||
|
||||
handleChange (e) {
|
||||
let id = e.target.id
|
||||
let value = e.target.value
|
||||
let error = this.validate({ id, value })
|
||||
switch (id) {
|
||||
case 'name':
|
||||
if (!isEmpty(error)) this.setState({ nameError: error })
|
||||
this.setState({ name: value })
|
||||
break
|
||||
case 'botName':
|
||||
if (!isEmpty(error)) this.setState({ botNameError: error })
|
||||
this.setState({ botName: value })
|
||||
break
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
async handleSubmit (e, createTeam, name, botName) {
|
||||
e.preventDefault()
|
||||
console.log('createTeam submit: ', name, botName)
|
||||
const slug = this.slugify(name)
|
||||
const botSlug = this.slugify(botName)
|
||||
await createTeam({ variables: { name, slug, botName, botSlug } })
|
||||
this.setState({ name: '', open: false })
|
||||
}
|
||||
|
||||
validate (data) {
|
||||
const errors = {}
|
||||
switch (data.id) {
|
||||
case 'name':
|
||||
if (data.value === '') {
|
||||
this.setState({ nameError: 'Please enter a team name' })
|
||||
} else {
|
||||
this.setState({ nameError: '' })
|
||||
}
|
||||
break
|
||||
case 'botName':
|
||||
if (data.value === '') {
|
||||
this.setState({ botNameError: 'Please enter a bot name' })
|
||||
} else {
|
||||
this.setState({ botNameError: '' })
|
||||
}
|
||||
break
|
||||
default:
|
||||
}
|
||||
return errors
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
CreateTeamDialog.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
authId: PropTypes.string
|
||||
}
|
||||
|
||||
export default withStyles(styles)(CreateTeamDialog)
|
||||
@@ -0,0 +1,156 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import { Mutation } from 'react-apollo'
|
||||
|
||||
import Button from '@material-ui/core/Button'
|
||||
import DeleteIcon from '@material-ui/icons/Delete'
|
||||
import Dialog from '@material-ui/core/Dialog'
|
||||
import DialogActions from '@material-ui/core/DialogActions'
|
||||
import DialogContent from '@material-ui/core/DialogContent'
|
||||
import DialogTitle from '@material-ui/core/DialogTitle'
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
|
||||
import DELETE_TEAM from '../../../graphql/teams/DeleteTeamMutation'
|
||||
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
|
||||
|
||||
import { checkGraphQLError } from '../../../utils/graphql-errors'
|
||||
|
||||
const styles = theme => ({
|
||||
dialogContainer: {
|
||||
display: 'block',
|
||||
margin: '3em',
|
||||
minWidth: 400
|
||||
},
|
||||
buttonRight: {
|
||||
justifyContent: 'flex-end'
|
||||
}
|
||||
})
|
||||
|
||||
export class ManageTeamDelete extends Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.handleClickOpen = this.handleClickOpen.bind(this)
|
||||
this.handleClose = this.handleClose.bind(this)
|
||||
this.handleChange = this.handleChange.bind(this)
|
||||
this.handleSubmit = this.handleSubmit.bind(this)
|
||||
|
||||
this.state = {
|
||||
open: false
|
||||
}
|
||||
}
|
||||
|
||||
handleClickOpen () {
|
||||
this.setState({ open: true })
|
||||
}
|
||||
|
||||
handleClose () {
|
||||
this.setState({ open: false })
|
||||
}
|
||||
|
||||
handleChange (e) {
|
||||
this.setState({ name: e.target.value })
|
||||
}
|
||||
|
||||
render () {
|
||||
console.log(this.props, this.props.slug)
|
||||
const { classes, authId } = this.props
|
||||
return (
|
||||
<Mutation
|
||||
mutation={DELETE_TEAM}
|
||||
refetchQueries={[
|
||||
{
|
||||
query: GET_TEAMS_BY_OWNER,
|
||||
variables: { authId }
|
||||
}
|
||||
]}
|
||||
>
|
||||
{(deleteTeam, { loading, error, data }) => {
|
||||
let errors
|
||||
let loader
|
||||
if (loading) {
|
||||
loader = (
|
||||
<Typography variant='caption'>Submitting team...</Typography>
|
||||
)
|
||||
}
|
||||
if (error) {
|
||||
errors = error.graphQLErrors.map(({ message }, i) => {
|
||||
const displayMessage = checkGraphQLError(message)
|
||||
console.log('createTeam error:', displayMessage)
|
||||
return (
|
||||
<Typography key={i} variant='caption'>
|
||||
{message}
|
||||
</Typography>
|
||||
)
|
||||
})
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
size='small'
|
||||
color='primary'
|
||||
className={classes.buttonRight}
|
||||
onClick={this.handleClickOpen}
|
||||
>
|
||||
<DeleteIcon /> Delete
|
||||
</Button>
|
||||
<Dialog
|
||||
open={this.state.open}
|
||||
onClose={this.handleClose}
|
||||
aria-labelledby='form-dialog-title'
|
||||
>
|
||||
<div classes={classes.dialogContainer}>
|
||||
<DialogTitle id='form-dialog-title'>
|
||||
Delete Team Team
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography variant='subtitle1' color='primary'>
|
||||
DANGER - Deleting your team cannot be undone
|
||||
</Typography>
|
||||
<Typography variant='subtitle1'>
|
||||
Are you sure you want to delete this team?
|
||||
</Typography>
|
||||
{loader}
|
||||
{errors}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color='primary'>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={e => {
|
||||
this.handleSubmit(
|
||||
e,
|
||||
deleteTeam,
|
||||
this.props.slug
|
||||
)
|
||||
}}
|
||||
color='primary'
|
||||
>
|
||||
Delete Team
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</Mutation>
|
||||
)
|
||||
}
|
||||
|
||||
async handleSubmit (e, deleteTeam, slug) {
|
||||
e.preventDefault()
|
||||
await deleteTeam({ variables: { slug } })
|
||||
this.setState({ open: false })
|
||||
}
|
||||
}
|
||||
|
||||
ManageTeamDelete.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
slug: PropTypes.string.isRequired,
|
||||
authId: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default withStyles(styles)(ManageTeamDelete)
|
||||
@@ -0,0 +1,171 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
|
||||
import Button from '@material-ui/core/Button'
|
||||
import DetailsIcon from '@material-ui/icons/Details'
|
||||
import Dialog from '@material-ui/core/Dialog'
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
import Card from '@material-ui/core/Card'
|
||||
import CardContent from '@material-ui/core/CardContent'
|
||||
import CardActions from '@material-ui/core/CardActions'
|
||||
import CardMedia from '@material-ui/core/CardMedia'
|
||||
|
||||
const styles = theme => ({
|
||||
dialogContainer: {
|
||||
display: 'block',
|
||||
margin: '3em',
|
||||
minWidth: 400
|
||||
},
|
||||
buttonRight: {
|
||||
justifyContent: 'flex-end'
|
||||
},
|
||||
cardGrid: {
|
||||
padding: `${theme.spacing.unit * 8}px 0`
|
||||
},
|
||||
card: {
|
||||
display: 'flex',
|
||||
width: '100%'
|
||||
},
|
||||
cardDetails: {
|
||||
display: 'flex',
|
||||
flex: 1
|
||||
},
|
||||
cardContent: {
|
||||
flex: 1
|
||||
},
|
||||
cardAvatarMedia: {
|
||||
flex: 1,
|
||||
width: 100,
|
||||
height: 100,
|
||||
maxWidth: 100,
|
||||
justifyContent: 'flex-start'
|
||||
},
|
||||
cardBannerMedia: {
|
||||
flex: 1,
|
||||
width: 600,
|
||||
height: 150,
|
||||
justifyContent: 'flex-start'
|
||||
}
|
||||
})
|
||||
|
||||
export class ManageTeamDetails extends Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.handleClickOpen = this.handleClickOpen.bind(this)
|
||||
this.handleClose = this.handleClose.bind(this)
|
||||
|
||||
this.state = {
|
||||
open: false
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
console.log(this.props.team)
|
||||
const { classes } = this.props
|
||||
const { name, members, profile, createdAt } = this.props.team
|
||||
let avatar
|
||||
let banner
|
||||
if (profile.avatar !== undefined && profile.avatar !== null) {
|
||||
avatar = profile.avatar
|
||||
} else {
|
||||
avatar = 'https://algobotcommstorage.blob.core.windows.net/aateammodule/aa-avatar-default.png'
|
||||
}
|
||||
if (profile.banner !== undefined && profile.banner !== null) {
|
||||
banner = profile.banner
|
||||
} else {
|
||||
banner = 'https://algobotcommstorage.blob.core.windows.net/aateammodule/aa-banner-default.png'
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
size='small'
|
||||
color='primary'
|
||||
className={this.props.classes.buttonRight}
|
||||
onClick={this.handleClickOpen}
|
||||
>
|
||||
<DetailsIcon /> Details
|
||||
</Button>
|
||||
<Dialog
|
||||
open={this.state.open}
|
||||
onClose={this.handleClose}
|
||||
aria-labelledby='form-dialog-title'
|
||||
>
|
||||
<div classes={classes.dialogContainer}>
|
||||
<Card className={classes.card}>
|
||||
<CardContent>
|
||||
<Typography variant='h6' id='form-dialog-title'>
|
||||
{name} Team Details
|
||||
</Typography>
|
||||
<CardMedia
|
||||
className={classes.cardBannerMedia}
|
||||
image={banner}
|
||||
title={`${name} ${banner}`}
|
||||
/>
|
||||
<CardMedia
|
||||
className={classes.cardAvatarMedia}
|
||||
image={avatar}
|
||||
title={`${name} ${avatar}`}
|
||||
/>
|
||||
<Typography
|
||||
variant='h2'
|
||||
align='center'
|
||||
color='textPrimary'
|
||||
gutterBottom
|
||||
>
|
||||
{name}
|
||||
</Typography>
|
||||
<Typography variant='subtitle1' color='textSecondary'>
|
||||
{createdAt}
|
||||
</Typography>
|
||||
<Typography variant='subtitle1' color='textSecondary'>
|
||||
Motto: {profile.motto}
|
||||
</Typography>
|
||||
<Typography variant='subtitle1' color='textSecondary'>
|
||||
Description: {profile.description}
|
||||
</Typography>
|
||||
<Typography variant='subtitle1' paragraph gutterBottom>
|
||||
Members: {members.length}
|
||||
</Typography>
|
||||
<Typography variant='subtitle1' color='primary'>
|
||||
Team Admin:
|
||||
{members.map(member => {
|
||||
if (member.role === 'OWNER' || member.role === 'ADMIN') {
|
||||
if (member.member !== null &&
|
||||
member.member.alias !== undefined &&
|
||||
member.member.alias !== null
|
||||
) {
|
||||
return member.member.alias
|
||||
}
|
||||
}
|
||||
})}
|
||||
</Typography>
|
||||
<CardActions>
|
||||
<Button onClick={this.handleClose} color='primary'>
|
||||
Close
|
||||
</Button>
|
||||
</CardActions>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
handleClickOpen () {
|
||||
this.setState({ open: true })
|
||||
}
|
||||
|
||||
handleClose () {
|
||||
this.setState({ open: false })
|
||||
}
|
||||
}
|
||||
|
||||
ManageTeamDetails.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
team: PropTypes.any
|
||||
}
|
||||
|
||||
export default withStyles(styles)(ManageTeamDetails)
|
||||
@@ -0,0 +1,282 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Mutation } from 'react-apollo'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
|
||||
import Button from '@material-ui/core/Button'
|
||||
import EditIcon from '@material-ui/icons/Edit'
|
||||
import TextField from '@material-ui/core/TextField'
|
||||
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 Typography from '@material-ui/core/Typography'
|
||||
|
||||
import { ImageUpload } from '@advancedalgos/web-components'
|
||||
|
||||
import UPDATE_TEAM_PROFILE from '../../../graphql/teams/UpdateTeamProfileMutation'
|
||||
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
|
||||
|
||||
import { checkGraphQLError } from '../../../utils/graphql-errors'
|
||||
|
||||
const styles = theme => ({
|
||||
dialogContainer: {
|
||||
display: 'block',
|
||||
margin: '3em',
|
||||
minWidth: 400
|
||||
},
|
||||
buttonRight: {
|
||||
justifyContent: 'flex-end'
|
||||
}
|
||||
})
|
||||
|
||||
export class ManageTeamEdit extends Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.handleClickOpen = this.handleClickOpen.bind(this)
|
||||
this.handleClose = this.handleClose.bind(this)
|
||||
this.handleChange = this.handleChange.bind(this)
|
||||
this.handleSubmit = this.handleSubmit.bind(this)
|
||||
this.handleAvatar = this.handleAvatar.bind(this)
|
||||
this.handleBanner = this.handleBanner.bind(this)
|
||||
|
||||
console.log('ManageTeamEdit', props.team)
|
||||
const motto = props.team.profile.motto || ''
|
||||
const description = props.team.profile.description || ''
|
||||
const avatar = props.team.profile.avatar || null
|
||||
const banner = props.team.profile.banner || null
|
||||
this.authId = props.authId
|
||||
|
||||
this.state = {
|
||||
open: false,
|
||||
motto: motto,
|
||||
description: description,
|
||||
avatar: avatar,
|
||||
banner: banner
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { classes, team, match } = this.props
|
||||
console.log('ManageTeamEdit ', this.props, this.props.slug, this.props.team, match)
|
||||
return (
|
||||
<Mutation
|
||||
mutation={UPDATE_TEAM_PROFILE}
|
||||
refetchQueries={[
|
||||
{
|
||||
query: GET_TEAMS_BY_OWNER,
|
||||
variables: { authId: this.authId }
|
||||
}
|
||||
]}
|
||||
>
|
||||
{(updateTeamProfile, { loading, error, data }) => {
|
||||
const AzureStorageUrl = process.env.AZURE_STORAGE_URL_TEAMS
|
||||
const AzureStorageSAS = process.env.AZURE_STORAGE_SAS_TEAMS
|
||||
const containerName = team.slug
|
||||
let avatar = null
|
||||
if (this.state.avatar === null && team.profile !== null && (team.profile.avatar === undefined || team.profile.avatar === null)) avatar = 'https://algobotcommstorage.blob.core.windows.net/aateammodule/aa-avatar-default.png'
|
||||
if (team.profile !== null && team.profile.avatar !== undefined && team.profile.avatar !== null) avatar = team.profile.avatar
|
||||
if (this.state.avatar !== null) avatar = this.state.avatar
|
||||
|
||||
let banner = null
|
||||
if (this.state.banner === null && team.profile !== null && (team.profile.banner === undefined || team.profile.banner === null)) banner = 'https://algobotcommstorage.blob.core.windows.net/aateammodule/aa-banner-default.png'
|
||||
if (team.profile !== null && team.profile.banner !== undefined && team.profile.banner !== null) banner = team.profile.banner
|
||||
if (this.state.banner !== null) banner = this.state.banner
|
||||
console.log('team images: ', avatar, banner)
|
||||
|
||||
let errors
|
||||
let loader
|
||||
if (loading) {
|
||||
loader = (
|
||||
<Typography variant='caption'>Submitting team...</Typography>
|
||||
)
|
||||
}
|
||||
if (error) {
|
||||
errors = error.graphQLErrors.map(({ message }, i) => {
|
||||
const displayMessage = checkGraphQLError(message)
|
||||
console.log('updateTeamProfile error:', displayMessage)
|
||||
return (
|
||||
<Typography key={i} variant='caption'>
|
||||
{message}
|
||||
</Typography>
|
||||
)
|
||||
})
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
size='small'
|
||||
color='primary'
|
||||
className={classes.buttonRight}
|
||||
onClick={this.handleClickOpen}
|
||||
>
|
||||
<EditIcon /> Edit
|
||||
</Button>
|
||||
<Dialog
|
||||
open={this.state.open}
|
||||
onClose={this.handleClose}
|
||||
aria-labelledby='form-dialog-title'
|
||||
>
|
||||
<div classes={classes.dialogContainer}>
|
||||
<DialogTitle id='form-dialog-title'>
|
||||
Edit Team Details
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<ImageUpload
|
||||
key='banner'
|
||||
handleUrl={this.handleBanner}
|
||||
fileName={`${team.slug}-banner.jpg`}
|
||||
containerName={containerName}
|
||||
existingImage={banner}
|
||||
imagePreviewConfig={{ width: 450, title: 'Change Banner' }}
|
||||
cropContainerConfig={{ x: 10, y: 10, width: 800, height: 200 }}
|
||||
cropPreviewBox={{ width: 650, height: 200 }}
|
||||
saveImageConfig={{
|
||||
quality: 0.6,
|
||||
maxWidth: 800,
|
||||
maxHeight: 200,
|
||||
autoRotate: true,
|
||||
mimeType: 'image/jpeg'
|
||||
}}
|
||||
AzureStorageUrl={AzureStorageUrl}
|
||||
AzureSASURL={AzureStorageSAS}
|
||||
cropRatio={4}
|
||||
debug
|
||||
/>
|
||||
<ImageUpload
|
||||
key='avatar1'
|
||||
handleUrl={this.handleAvatar}
|
||||
fileName={`${team.slug}-avatar.jpg`}
|
||||
containerName={containerName}
|
||||
existingImage={avatar}
|
||||
imagePreviewConfig={{ width: 200, title: 'Change Avatar' }}
|
||||
cropContainerConfig={{ x: 10, y: 10, width: 200, height: 200 }}
|
||||
cropPreviewBox={{ width: 350, height: 350 }}
|
||||
saveImageConfig={{
|
||||
quality: 0.6,
|
||||
maxWidth: 200,
|
||||
maxHeight: 200,
|
||||
autoRotate: true,
|
||||
mimeType: 'image/jpeg'
|
||||
}}
|
||||
AzureStorageUrl={AzureStorageUrl}
|
||||
AzureSASURL={AzureStorageSAS}
|
||||
cropRatio={1}
|
||||
debug
|
||||
/>
|
||||
<TextField
|
||||
autoFocus
|
||||
margin='dense'
|
||||
id='name'
|
||||
label='Team Name'
|
||||
type='text'
|
||||
fullWidth
|
||||
disabled
|
||||
value={team.name}
|
||||
/>
|
||||
<TextField
|
||||
autoFocus
|
||||
margin='dense'
|
||||
id='motto'
|
||||
label='Team Motto'
|
||||
type='text'
|
||||
fullWidth
|
||||
value={this.state.motto}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<DialogContentText>Team description:</DialogContentText>
|
||||
<TextField
|
||||
margin='dense'
|
||||
id='description'
|
||||
label='Team Description'
|
||||
type='text'
|
||||
rows={4}
|
||||
multiline
|
||||
fullWidth
|
||||
value={this.state.description}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{loader}
|
||||
{errors}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color='primary'>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={e => {
|
||||
this.handleSubmit(e, updateTeamProfile, this.props.slug)
|
||||
}}
|
||||
color='primary'
|
||||
>
|
||||
Update Team
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</Mutation>
|
||||
)
|
||||
}
|
||||
|
||||
handleClickOpen () {
|
||||
this.setState({ open: true })
|
||||
}
|
||||
|
||||
handleClose () {
|
||||
this.setState({ open: false })
|
||||
}
|
||||
|
||||
handleChange (e) {
|
||||
switch (e.target.id) {
|
||||
case 'motto':
|
||||
this.setState({ motto: e.target.value })
|
||||
break
|
||||
case 'description':
|
||||
this.setState({ description: e.target.value })
|
||||
break
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
handleAvatar (avatarUrl) {
|
||||
console.log('handleAvatar: ', avatarUrl)
|
||||
this.setState({ avatar: `${avatarUrl}?${Math.random()}` })
|
||||
}
|
||||
|
||||
handleBanner (bannerUrl) {
|
||||
console.log('handleBanner: ', bannerUrl)
|
||||
this.setState({ banner: `${bannerUrl}?${Math.random()}` })
|
||||
}
|
||||
|
||||
async handleSubmit (e, updateTeamProfile, slug) {
|
||||
console.log('handleSubmit: ', this.state)
|
||||
e.preventDefault()
|
||||
|
||||
await updateTeamProfile({
|
||||
variables: {
|
||||
slug,
|
||||
owner: this.authId,
|
||||
description: this.state.description,
|
||||
motto: this.state.motto,
|
||||
avatar: this.state.avatar,
|
||||
banner: this.state.banner
|
||||
}
|
||||
})
|
||||
this.setState({ description: '', motto: '', open: false })
|
||||
}
|
||||
}
|
||||
|
||||
ManageTeamEdit.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
slug: PropTypes.string.isRequired,
|
||||
team: PropTypes.object,
|
||||
authId: PropTypes.string.isRequired,
|
||||
match: PropTypes.object
|
||||
}
|
||||
|
||||
export default withStyles(styles)(ManageTeamEdit)
|
||||
@@ -0,0 +1,142 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Query } from 'react-apollo'
|
||||
import { withStateHandlers, lifecycle, compose } from 'recompose'
|
||||
|
||||
import Grid from '@material-ui/core/Grid'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
|
||||
import { isDefined, isString } from '../../../utils/js-helpers'
|
||||
import { getItem } from '../../../utils/local-storage'
|
||||
|
||||
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
|
||||
|
||||
import ManageMembersTeamItem from './ManageMembersTeamItem'
|
||||
import { MessageCard } from '@advancedalgos/web-components'
|
||||
|
||||
const styles = theme => ({
|
||||
heroContent: {
|
||||
maxWidth: 600,
|
||||
margin: '0 auto',
|
||||
padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px`
|
||||
},
|
||||
cardGrid: {
|
||||
padding: `${theme.spacing.unit * 8}px 0`
|
||||
},
|
||||
buttonRight: {
|
||||
justifyContent: 'flex-end'
|
||||
},
|
||||
card: {
|
||||
display: 'flex',
|
||||
width: '100%'
|
||||
},
|
||||
cardDetails: {
|
||||
display: 'flex',
|
||||
flex: 1
|
||||
},
|
||||
cardContent: {
|
||||
flex: 1
|
||||
},
|
||||
cardMedia: {
|
||||
flex: 1,
|
||||
width: 100,
|
||||
height: 100,
|
||||
maxWidth: 100,
|
||||
justifyContent: 'flex-start'
|
||||
}
|
||||
})
|
||||
|
||||
export const ManageTeamMembersList = ({ classes, user = null }) => {
|
||||
let owner
|
||||
let authId = null
|
||||
console.log('ManageTeamsList: ', user)
|
||||
if (user !== null && isString(user)) {
|
||||
owner = JSON.parse(user)
|
||||
if (isDefined(owner.authId)) authId = owner.authId
|
||||
}
|
||||
console.log('ManageTeamsList 2: ', owner, authId)
|
||||
if (authId === undefined || authId === null) {
|
||||
return (
|
||||
<Grid container spacing={40}>
|
||||
<Grid>
|
||||
<MessageCard message='Loading...' />
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Query
|
||||
query={GET_TEAMS_BY_OWNER}
|
||||
variables={{ authId }}
|
||||
fetchPolicy='network-only'
|
||||
>
|
||||
{({ loading, error, data }) => {
|
||||
console.log('GET_TEAMS_BY_OWNER: ', loading, error, data)
|
||||
let errors = null
|
||||
if (error) {
|
||||
errors = error.graphQLErrors.map(({ message }, i) => {
|
||||
return <MessageCard message={message} />
|
||||
})
|
||||
}
|
||||
if (!loading && !error) {
|
||||
if (data.teams_TeamsByOwner.length > 0) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Grid container spacing={40}>
|
||||
{!loading &&
|
||||
data.teams_TeamsByOwner.map(team => (
|
||||
<ManageMembersTeamItem key={team.id} team={team} authId={authId} />
|
||||
))
|
||||
}
|
||||
{errors}
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Grid container spacing={40}>
|
||||
<Grid item xs={10}>
|
||||
<MessageCard message='You don’t have any members. Somethings not right...' />
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<Grid container spacing={40}>
|
||||
<Grid item xs={12}>
|
||||
<MessageCard message='Loading...' />
|
||||
{errors !== null && <MessageCard message={errors} />}
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
}}
|
||||
</Query>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ManageTeamMembersList.propTypes = {
|
||||
user: PropTypes.any,
|
||||
classes: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
const getUserOnMount = lifecycle({
|
||||
componentDidMount () {
|
||||
getItem('user').then(user => {
|
||||
this.setState({ user })
|
||||
}) // Set user to state
|
||||
}
|
||||
})
|
||||
|
||||
const mapStateToProps = withStateHandlers(() => ({ user: null }), {
|
||||
user: ({ user }) => () => ({ user })
|
||||
})
|
||||
|
||||
const ManageTeamMembersListAuthId = compose(
|
||||
mapStateToProps,
|
||||
getUserOnMount
|
||||
)(ManageTeamMembersList)
|
||||
|
||||
export default withStyles(styles)(ManageTeamMembersListAuthId)
|
||||
@@ -0,0 +1,57 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import Grid from '@material-ui/core/Grid'
|
||||
import Card from '@material-ui/core/Card'
|
||||
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 ManageTeamDetails from './ManageTeamDetails'
|
||||
import ManageTeamDelete from './ManageTeamDelete'
|
||||
import ManageTeamEdit from './ManageTeamEdit'
|
||||
|
||||
export const ManageTeamsItem = ({ classes, team, authId, ...props }) => {
|
||||
console.log('ManageTeamsItem', team, team.profile, team.profile.avatar)
|
||||
let avatar
|
||||
if (team.profile.avatar !== undefined && team.profile.avatar !== 'a') {
|
||||
avatar = team.profile.avatar
|
||||
} else {
|
||||
avatar = 'https://algobotcommstorage.blob.core.windows.net/aateammodule/aa-avatar-default.png'
|
||||
}
|
||||
return (
|
||||
<Grid item xs={12}>
|
||||
<Card className={classes.card}>
|
||||
<div className={classes.cardDetails}>
|
||||
<CardMedia
|
||||
className={classes.cardMedia}
|
||||
image={avatar}
|
||||
title={team.name}
|
||||
/>
|
||||
<CardContent className={classes.cardContent}>
|
||||
<Typography gutterBottom variant='h5' component='h2'>
|
||||
{team.name}
|
||||
</Typography>
|
||||
<Typography variant='caption' color='textSecondary'>
|
||||
{team.createdAt} | Members: {team.members.length}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
<CardActions>
|
||||
<ManageTeamDetails team={team} />
|
||||
<ManageTeamEdit slug={team.slug} team={team} authId={authId} {...props} />
|
||||
<ManageTeamDelete slug={team.slug} authId={authId} />
|
||||
</CardActions>
|
||||
</div>
|
||||
</Card>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
|
||||
ManageTeamsItem.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
team: PropTypes.object.isRequired,
|
||||
authId: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default ManageTeamsItem
|
||||
@@ -0,0 +1,151 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Query } from 'react-apollo'
|
||||
import { withStateHandlers, lifecycle, compose } from 'recompose'
|
||||
|
||||
import Grid from '@material-ui/core/Grid'
|
||||
import { MessageCard } from '@advancedalgos/web-components'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
|
||||
import { isDefined, isString } from '../../../utils/js-helpers'
|
||||
import { getItem } from '../../../utils/local-storage'
|
||||
|
||||
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
|
||||
|
||||
import ManageTeamsItem from './ManageTeamsItem'
|
||||
import CreateTeamDialog from './CreateTeamDialog'
|
||||
|
||||
const styles = theme => ({
|
||||
heroContent: {
|
||||
maxWidth: 600,
|
||||
margin: '0 auto',
|
||||
padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px`
|
||||
},
|
||||
cardGrid: {
|
||||
padding: `${theme.spacing.unit * 8}px 0`
|
||||
},
|
||||
buttonRight: {
|
||||
justifyContent: 'flex-end'
|
||||
},
|
||||
card: {
|
||||
display: 'flex',
|
||||
width: '100%'
|
||||
},
|
||||
cardDetails: {
|
||||
display: 'flex',
|
||||
flex: 1
|
||||
},
|
||||
cardContent: {
|
||||
flex: 1
|
||||
},
|
||||
cardMedia: {
|
||||
flex: 1,
|
||||
width: 100,
|
||||
height: 100,
|
||||
maxWidth: 100,
|
||||
justifyContent: 'flex-start'
|
||||
}
|
||||
})
|
||||
|
||||
export const ManageTeamsList = ({ classes, user = null, ...props }) => {
|
||||
let owner
|
||||
let authId = null
|
||||
console.log('ManageTeamsList: ', user)
|
||||
if (user !== null && isString(user)) {
|
||||
owner = JSON.parse(user)
|
||||
if (isDefined(owner.authId)) authId = owner.authId
|
||||
}
|
||||
console.log('ManageTeamsList 2: ', owner, authId)
|
||||
if (authId === undefined || authId === null) {
|
||||
return (
|
||||
<Grid container spacing={40}>
|
||||
<Grid>
|
||||
<MessageCard message='Loading...' />
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Query
|
||||
query={GET_TEAMS_BY_OWNER}
|
||||
variables={{ authId }}
|
||||
fetchPolicy='network-only'
|
||||
>
|
||||
{({ loading, error, data }) => {
|
||||
console.log('GET_TEAMS_BY_OWNER: ', loading, error, data)
|
||||
|
||||
let errors = null
|
||||
if (error) {
|
||||
errors = error.graphQLErrors.map(({ message }, i) => {
|
||||
return <MessageCard message={message} />
|
||||
})
|
||||
}
|
||||
if (!loading && !error) {
|
||||
if (data.teams_TeamsByOwner.length > 0) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Grid container spacing={40}>
|
||||
{!loading &&
|
||||
data.teams_TeamsByOwner.map(team => (
|
||||
<ManageTeamsItem
|
||||
key={team.id}
|
||||
team={team}
|
||||
classes={classes}
|
||||
authId={authId}
|
||||
{...props}
|
||||
/>
|
||||
))}
|
||||
{errors}
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Grid container spacing={40}>
|
||||
<Grid item xs={10}>
|
||||
<MessageCard message='You don’t have any teams. Create one!'>
|
||||
<CreateTeamDialog authId={authId} />
|
||||
</MessageCard>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<Grid container spacing={40}>
|
||||
<Grid item xs={12}>
|
||||
<MessageCard message='Loading...' />
|
||||
{errors !== null && <MessageCard message={errors} />}
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
}}
|
||||
</Query>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ManageTeamsList.propTypes = {
|
||||
user: PropTypes.any,
|
||||
classes: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
const getUserOnMount = lifecycle({
|
||||
componentDidMount () {
|
||||
getItem('user').then(user => {
|
||||
this.setState({ user })
|
||||
}) // Set user to state
|
||||
}
|
||||
})
|
||||
|
||||
const mapStateToProps = withStateHandlers(() => ({ user: null }), {
|
||||
user: ({ user }) => () => ({ user })
|
||||
})
|
||||
|
||||
const ManageTeamsListAuthId = compose(
|
||||
mapStateToProps,
|
||||
getUserOnMount
|
||||
)(ManageTeamsList)
|
||||
|
||||
export default withStyles(styles)(ManageTeamsListAuthId)
|
||||
@@ -0,0 +1,28 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
|
||||
import ManageTeamsList from './components/ManageTeamsList'
|
||||
|
||||
const styles = theme => ({
|
||||
tableContainer: {
|
||||
height: 320
|
||||
}
|
||||
})
|
||||
|
||||
const ManageTeams = ({ classes, ...props }) => (
|
||||
<div>
|
||||
<Typography variant='h4' gutterBottom>
|
||||
Manage Your Teams
|
||||
</Typography>
|
||||
<ManageTeamsList {...props} />
|
||||
</div>
|
||||
)
|
||||
|
||||
ManageTeams.propTypes = {
|
||||
classes: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
export default withStyles(styles)(ManageTeams)
|
||||
@@ -0,0 +1,59 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
|
||||
import Grid from '@material-ui/core/Grid'
|
||||
import { MessageCard } from '@advancedalgos/web-components'
|
||||
|
||||
const styles = theme => ({
|
||||
heroContent: {
|
||||
maxWidth: 600,
|
||||
margin: '0 auto',
|
||||
padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px`
|
||||
},
|
||||
cardGrid: {
|
||||
padding: `${theme.spacing.unit * 8}px 0`
|
||||
},
|
||||
buttonRight: {
|
||||
justifyContent: 'flex-end'
|
||||
},
|
||||
card: {
|
||||
display: 'flex',
|
||||
width: '100%'
|
||||
},
|
||||
cardDetails: {
|
||||
display: 'flex',
|
||||
flex: 1
|
||||
},
|
||||
cardContent: {
|
||||
flex: 1
|
||||
},
|
||||
cardMedia: {
|
||||
flex: 1,
|
||||
width: 100,
|
||||
height: 100,
|
||||
maxWidth: 100,
|
||||
justifyContent: 'flex-start'
|
||||
}
|
||||
})
|
||||
|
||||
export const Settings = ({ classes }) => (
|
||||
<Grid container spacing={40}>
|
||||
<Grid>
|
||||
<Typography variant='h4' gutterBottom>
|
||||
Settings
|
||||
</Typography>
|
||||
<div className={classes.tableContainer}>
|
||||
<MessageCard message='Coming soon. Management settings.' />
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
|
||||
Settings.propTypes = {
|
||||
classes: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
export default withStyles(styles)(Settings)
|
||||
@@ -0,0 +1,152 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import { Mutation } from 'react-apollo'
|
||||
|
||||
import Button from '@material-ui/core/Button'
|
||||
import PersonAddDisabledIcon from '@material-ui/icons/PersonAddDisabled'
|
||||
import Dialog from '@material-ui/core/Dialog'
|
||||
import DialogActions from '@material-ui/core/DialogActions'
|
||||
import DialogContent from '@material-ui/core/DialogContent'
|
||||
import DialogTitle from '@material-ui/core/DialogTitle'
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
|
||||
import REMOVE_TEAM_MEMBER from '../../../graphql/teams/RemoveTeamMemberMutation'
|
||||
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
|
||||
|
||||
import { checkGraphQLError } from '../../../utils/graphql-errors'
|
||||
|
||||
const styles = theme => ({
|
||||
dialogContainer: {
|
||||
display: 'block',
|
||||
margin: '3em',
|
||||
minWidth: 400
|
||||
},
|
||||
buttonRight: {
|
||||
justifyContent: 'flex-end'
|
||||
}
|
||||
})
|
||||
|
||||
export class ManageMemberDelete extends Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.handleClickOpen = this.handleClickOpen.bind(this)
|
||||
this.handleClose = this.handleClose.bind(this)
|
||||
this.handleChange = this.handleChange.bind(this)
|
||||
this.handleSubmit = this.handleSubmit.bind(this)
|
||||
|
||||
this.state = {
|
||||
open: false
|
||||
}
|
||||
}
|
||||
|
||||
handleClickOpen () {
|
||||
this.setState({ open: true })
|
||||
}
|
||||
|
||||
handleClose () {
|
||||
this.setState({ open: false })
|
||||
}
|
||||
|
||||
handleChange (e) {
|
||||
this.setState({ name: e.target.value })
|
||||
}
|
||||
|
||||
render () {
|
||||
console.log(this.props, this.props.teamId)
|
||||
const { classes, teamId, authId } = this.props
|
||||
return (
|
||||
<Mutation
|
||||
mutation={REMOVE_TEAM_MEMBER}
|
||||
refetchQueries={[{ query: GET_TEAMS_BY_OWNER }]}
|
||||
>
|
||||
{(deleteTeam, { loading, error, data }) => {
|
||||
let errors
|
||||
let loader
|
||||
if (loading) {
|
||||
loader = (
|
||||
<Typography variant='caption'>Submitting team...</Typography>
|
||||
)
|
||||
}
|
||||
if (error) {
|
||||
errors = error.graphQLErrors.map(({ message }, i) => {
|
||||
const displayMessage = checkGraphQLError(message)
|
||||
console.log('createTeam error:', displayMessage)
|
||||
return (
|
||||
<Typography key={i} variant='caption'>
|
||||
{message}
|
||||
</Typography>
|
||||
)
|
||||
})
|
||||
}
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Button
|
||||
size='small'
|
||||
color='primary'
|
||||
className={classes.buttonRight}
|
||||
onClick={this.handleClickOpen}
|
||||
>
|
||||
<PersonAddDisabledIcon /> Remove
|
||||
</Button>
|
||||
<Dialog
|
||||
open={this.state.open}
|
||||
onClose={this.handleClose}
|
||||
aria-labelledby='form-dialog-title'
|
||||
>
|
||||
<div classes={classes.dialogContainer}>
|
||||
<DialogTitle id='form-dialog-title'>
|
||||
Remove Team Member
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography variant='subtitle1' color='primary'>
|
||||
DANGER - Removing your team cannot be undone
|
||||
</Typography>
|
||||
<Typography variant='subtitle1'>
|
||||
Are you sure you want to remove this team member?
|
||||
</Typography>
|
||||
{loader}
|
||||
{errors}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color='primary'>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={e => {
|
||||
this.handleSubmit(
|
||||
e,
|
||||
deleteTeam,
|
||||
teamId,
|
||||
authId
|
||||
)
|
||||
}}
|
||||
color='primary'
|
||||
>
|
||||
Remove Member
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</div>
|
||||
</Dialog>
|
||||
</React.Fragment>
|
||||
)
|
||||
}}
|
||||
</Mutation>
|
||||
)
|
||||
}
|
||||
|
||||
async handleSubmit (e, deleteTeam, teamId, memberId) {
|
||||
e.preventDefault()
|
||||
await deleteTeam({ variables: { teamId, memberId } })
|
||||
this.setState({ open: false })
|
||||
}
|
||||
}
|
||||
|
||||
ManageMemberDelete.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
teamId: PropTypes.string.isRequired,
|
||||
authId: PropTypes.string
|
||||
}
|
||||
|
||||
export default withStyles(styles)(ManageMemberDelete)
|
||||
@@ -0,0 +1,169 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import { Mutation } from 'react-apollo'
|
||||
|
||||
import Button from '@material-ui/core/Button'
|
||||
import AssignmentIndIcon from '@material-ui/icons/AssignmentInd'
|
||||
import Dialog from '@material-ui/core/Dialog'
|
||||
import DialogActions from '@material-ui/core/DialogActions'
|
||||
import DialogContent from '@material-ui/core/DialogContent'
|
||||
import DialogTitle from '@material-ui/core/DialogTitle'
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
import TextField from '@material-ui/core/TextField'
|
||||
import MenuItem from '@material-ui/core/MenuItem'
|
||||
|
||||
import SET_TEAM_MEMBER_ROLE from '../../../graphql/teams/SetTeamMemberRoleMutation'
|
||||
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
|
||||
|
||||
import { checkGraphQLError } from '../../../utils/graphql-errors'
|
||||
|
||||
const styles = theme => ({
|
||||
dialogContainer: {
|
||||
display: 'block',
|
||||
margin: '3em',
|
||||
minWidth: 400
|
||||
},
|
||||
buttonRight: {
|
||||
justifyContent: 'flex-end'
|
||||
}
|
||||
})
|
||||
|
||||
const roles = [
|
||||
{ role: 'Admin' },
|
||||
{ role: 'Member' }
|
||||
]
|
||||
|
||||
export class ManageMemberRole extends Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.handleClickOpen = this.handleClickOpen.bind(this)
|
||||
this.handleClose = this.handleClose.bind(this)
|
||||
this.handleChange = this.handleChange.bind(this)
|
||||
this.handleSubmit = this.handleSubmit.bind(this)
|
||||
|
||||
this.state = {
|
||||
open: false,
|
||||
role: ''
|
||||
}
|
||||
}
|
||||
|
||||
handleClickOpen () {
|
||||
this.setState({ open: true })
|
||||
}
|
||||
|
||||
handleClose () {
|
||||
this.setState({ open: false })
|
||||
}
|
||||
|
||||
handleChange (e) {
|
||||
this.setState({ name: e.target.value })
|
||||
}
|
||||
|
||||
render () {
|
||||
console.log(this.props, this.props.teamId)
|
||||
const { classes, teamId, authId } = this.props
|
||||
return (
|
||||
<Mutation
|
||||
mutation={SET_TEAM_MEMBER_ROLE}
|
||||
refetchQueries={[{ query: GET_TEAMS_BY_OWNER }]}
|
||||
>
|
||||
{(setTeamMemberRole, { loading, error, data }) => {
|
||||
let errors
|
||||
let loader
|
||||
if (loading) {
|
||||
loader = (
|
||||
<Typography variant='caption'>Submitting team...</Typography>
|
||||
)
|
||||
}
|
||||
if (error) {
|
||||
errors = error.graphQLErrors.map(({ message }, i) => {
|
||||
const displayMessage = checkGraphQLError(message)
|
||||
console.log('createTeam error:', displayMessage)
|
||||
return (
|
||||
<Typography key={i} variant='caption'>
|
||||
{message}
|
||||
</Typography>
|
||||
)
|
||||
})
|
||||
}
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Button
|
||||
size='small'
|
||||
color='primary'
|
||||
className={classes.buttonRight}
|
||||
onClick={this.handleClickOpen}
|
||||
>
|
||||
<AssignmentIndIcon /> Set Role
|
||||
</Button>
|
||||
<Dialog
|
||||
open={this.state.open}
|
||||
onClose={this.handleClose}
|
||||
aria-labelledby='form-dialog-title'
|
||||
>
|
||||
<div classes={classes.dialogContainer}>
|
||||
<DialogTitle id='form-dialog-title'>
|
||||
Set Team Member Role
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography variant='subtitle1'>
|
||||
Admin members can approve new team members, send team invitations, and remove team members.
|
||||
</Typography>
|
||||
<TextField
|
||||
select
|
||||
label='Team Role'
|
||||
value={this.state.role}
|
||||
onChange={(e) => this.setState({ role: e.target.value })}
|
||||
fullWidth
|
||||
>
|
||||
{roles.map(role => (
|
||||
<MenuItem key={role.role} value={role.role}>{role.role}</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
{loader}
|
||||
{errors}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color='primary'>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={e => {
|
||||
this.handleSubmit(
|
||||
e,
|
||||
setTeamMemberRole,
|
||||
teamId,
|
||||
authId
|
||||
)
|
||||
}}
|
||||
color='primary'
|
||||
>
|
||||
Set Member Role
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</div>
|
||||
</Dialog>
|
||||
</React.Fragment>
|
||||
)
|
||||
}}
|
||||
</Mutation>
|
||||
)
|
||||
}
|
||||
|
||||
async handleSubmit (e, setTeamMemberRole, teamId, authId) {
|
||||
e.preventDefault()
|
||||
const role = this.state.role
|
||||
await setTeamMemberRole({ variables: { teamId, memberId: authId, role: role } })
|
||||
this.setState({ open: false })
|
||||
}
|
||||
}
|
||||
|
||||
ManageMemberRole.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
teamId: PropTypes.string.isRequired,
|
||||
authId: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default withStyles(styles)(ManageMemberRole)
|
||||
@@ -0,0 +1,99 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
|
||||
import Button from '@material-ui/core/Button'
|
||||
import HistoryIcon from '@material-ui/icons/History'
|
||||
import Dialog from '@material-ui/core/Dialog'
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
import Card from '@material-ui/core/Card'
|
||||
import CardContent from '@material-ui/core/CardContent'
|
||||
import CardActions from '@material-ui/core/CardActions'
|
||||
|
||||
const styles = theme => ({
|
||||
dialogContainer: {
|
||||
display: 'block',
|
||||
margin: '3em',
|
||||
minWidth: 400
|
||||
},
|
||||
buttonRight: {
|
||||
justifyContent: 'flex-end'
|
||||
}
|
||||
})
|
||||
|
||||
export class ManageMemberStatus extends Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.handleClickOpen = this.handleClickOpen.bind(this)
|
||||
this.handleClose = this.handleClose.bind(this)
|
||||
|
||||
this.state = {
|
||||
open: false,
|
||||
role: ''
|
||||
}
|
||||
}
|
||||
|
||||
handleClickOpen () {
|
||||
this.setState({ open: true })
|
||||
}
|
||||
|
||||
handleClose () {
|
||||
this.setState({ open: false })
|
||||
}
|
||||
|
||||
handleChange (e) {
|
||||
this.setState({ name: e.target.value })
|
||||
}
|
||||
|
||||
render () {
|
||||
console.log(this.props, this.props.status)
|
||||
const { classes, status } = this.props
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
size='small'
|
||||
color='primary'
|
||||
className={this.props.classes.buttonRight}
|
||||
onClick={this.handleClickOpen}
|
||||
>
|
||||
<HistoryIcon /> Status Details
|
||||
</Button>
|
||||
<Dialog
|
||||
open={this.state.open}
|
||||
onClose={this.handleClose}
|
||||
aria-labelledby='form-dialog-title'
|
||||
>
|
||||
<div classes={classes.dialogContainer}>
|
||||
<Card className={classes.card}>
|
||||
<CardContent>
|
||||
<Typography variant='h6' id='form-dialog-title'>
|
||||
Member Status Details
|
||||
</Typography>
|
||||
{status !== null && status.map(stat => {
|
||||
return (
|
||||
<Typography variant='h6' id='form-dialog-title' key={stat.createdAt}>
|
||||
{stat.status} | {stat.reason} | {stat.createdAt}
|
||||
</Typography>
|
||||
)
|
||||
})}
|
||||
<CardActions>
|
||||
<Button onClick={this.handleClose} color='primary'>
|
||||
Close
|
||||
</Button>
|
||||
</CardActions>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ManageMemberStatus.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
status: PropTypes.array
|
||||
}
|
||||
|
||||
export default withStyles(styles)(ManageMemberStatus)
|
||||
@@ -0,0 +1,64 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import Grid from '@material-ui/core/Grid'
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
|
||||
import ManageMemberDelete from './ManageMemberDelete'
|
||||
import ManageMemberRole from './ManageMemberRole'
|
||||
import ManageMemberStatus from './ManageMemberStatus'
|
||||
import { MessageCard } from '@advancedalgos/web-components'
|
||||
|
||||
export const ManageMembersItem = ({ classes, member, teamId, authId }) => {
|
||||
console.log('ManageMembersItem', member)
|
||||
let profile = null
|
||||
let email = null
|
||||
let memberStatus = null
|
||||
if (member.member !== null) {
|
||||
profile = member.member
|
||||
}
|
||||
if (member.member === null && member.email !== null) {
|
||||
email = member.email
|
||||
}
|
||||
if (member.status.length > 0) memberStatus = member.status
|
||||
if (profile !== null || email !== null) {
|
||||
return (
|
||||
<Grid container className={classes.memberContainer}>
|
||||
<Grid item xs={4}>
|
||||
<Typography gutterBottom variant='subtitle1' component='h2' align='left' >
|
||||
{profile !== null ? profile.alias : email}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<Typography color='textSecondary' variant='body2' component='h4' align='left' >
|
||||
{email !== null ? `${memberStatus[memberStatus.length - 1].status} | Sent: ${memberStatus[memberStatus.length - 1].createdAt}` : `${member.role} | Member since: `}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
{ profile !== null && member.role !== 'OWNER' && (
|
||||
<ManageMemberRole teamId={teamId} authId={profile !== null ? profile.authId : null} className={classes.buttonRight} />
|
||||
)}
|
||||
{(email !== null || member.role !== 'OWNER') && (
|
||||
<ManageMemberStatus status={member.status} className={classes.buttonRight} />
|
||||
)}
|
||||
{(email !== null || member.role !== 'OWNER') && (
|
||||
<ManageMemberDelete teamId={teamId} authId={profile !== null ? profile.authId : null} email={email !== null ? email : null} className={classes.buttonRight} />
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<MessageCard message='No Member info found' />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ManageMembersItem.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
member: PropTypes.object.isRequired,
|
||||
teamId: PropTypes.string.isRequired,
|
||||
authId: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default ManageMembersItem
|
||||
@@ -0,0 +1,116 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
|
||||
import Grid from '@material-ui/core/Grid'
|
||||
import Card from '@material-ui/core/Card'
|
||||
import CardContent from '@material-ui/core/CardContent'
|
||||
import CardMedia from '@material-ui/core/CardMedia'
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
|
||||
import InviteMemberDialog from './InviteMemberDialog'
|
||||
import ManageMembersItem from './ManageMembersItem'
|
||||
import { MessageCard } from '@advancedalgos/web-components'
|
||||
|
||||
const styles = theme => ({
|
||||
heroContent: {
|
||||
maxWidth: 600,
|
||||
margin: '0 auto',
|
||||
padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px`
|
||||
},
|
||||
cardGrid: {
|
||||
padding: `${theme.spacing.unit * 8}px 0`
|
||||
},
|
||||
buttonRight: {
|
||||
justifyContent: 'flex-end'
|
||||
},
|
||||
card: {
|
||||
display: 'flex',
|
||||
width: '100%'
|
||||
},
|
||||
cardDetails: {
|
||||
display: 'flex',
|
||||
flex: 1
|
||||
},
|
||||
cardContent: {
|
||||
flex: 1
|
||||
},
|
||||
cardMedia: {
|
||||
flex: 1,
|
||||
width: 100,
|
||||
height: 100,
|
||||
maxWidth: 100,
|
||||
justifyContent: 'flex-start'
|
||||
},
|
||||
cardMemberMedia: {
|
||||
flex: 1,
|
||||
width: 36,
|
||||
height: 36,
|
||||
maxWidth: 36,
|
||||
justifyContent: 'flex-start'
|
||||
},
|
||||
memberContainer: {
|
||||
margin: 10,
|
||||
padding: 6
|
||||
}
|
||||
})
|
||||
|
||||
export const ManageMembersTeamItem = ({ classes, team, authId }) => {
|
||||
console.log('ManageMembersItem', team, team.profile, team.profile.avatar)
|
||||
let avatar
|
||||
if (team.profile.avatar !== undefined && team.profile.avatar !== 'a') {
|
||||
avatar = team.profile.avatar
|
||||
} else {
|
||||
avatar = 'https://algobotcommstorage.blob.core.windows.net/aateammodule/aa-avatar-default.png'
|
||||
}
|
||||
if (team.members.length > 0) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12} key={team.id}>
|
||||
<Card className={classes.card}>
|
||||
<div className={classes.cardDetails}>
|
||||
<CardContent className={classes.cardContent}>
|
||||
<Grid container>
|
||||
<Grid item xs={2}>
|
||||
<CardMedia
|
||||
className={classes.cardMedia}
|
||||
image={avatar}
|
||||
title={team.name}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={9}>
|
||||
<Typography gutterBottom variant='h5' component='h2'>
|
||||
{team.name}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={1}>
|
||||
<InviteMemberDialog teamId={team.id} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
{team.members.length > 0 && team.members.map((member, index) => (
|
||||
<ManageMembersItem
|
||||
member={member}
|
||||
teamId={team.id}
|
||||
authId={authId}
|
||||
classes={classes}
|
||||
key={`${team.id}-${index}`}
|
||||
/>
|
||||
))}
|
||||
</CardContent>
|
||||
</div>
|
||||
</Card>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
)
|
||||
} else {
|
||||
return <MessageCard message='No Member info found' />
|
||||
}
|
||||
}
|
||||
|
||||
ManageMembersTeamItem.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
team: PropTypes.object.isRequired,
|
||||
authId: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default withStyles(styles)(ManageMembersTeamItem)
|
||||
@@ -0,0 +1,30 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
|
||||
// import ManageTeamMembersList from './components/ManageTeamMembersList'
|
||||
import { MessageCard } from '@advancedalgos/web-components'
|
||||
|
||||
const styles = theme => ({
|
||||
tableContainer: {
|
||||
height: 320
|
||||
}
|
||||
})
|
||||
|
||||
const TeamMembers = ({ classes }) => (
|
||||
<div>
|
||||
<Typography variant='h4' gutterBottom>
|
||||
Team Members
|
||||
<MessageCard message='Coming soon. Invite and manage team members.' />
|
||||
</Typography>
|
||||
|
||||
</div>
|
||||
)
|
||||
|
||||
TeamMembers.propTypes = {
|
||||
classes: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
export default withStyles(styles)(TeamMembers)
|
||||
@@ -58,13 +58,13 @@ const styles = theme => ({
|
||||
|
||||
const TeamsDetails = ({ classes, team }) => {
|
||||
let avatar
|
||||
if (team.profile.avatar !== undefined && team.profile.avatar !== 'a') {
|
||||
if (team.profile.avatar !== undefined && team.profile.avatar !== null) {
|
||||
avatar = team.profile.avatar
|
||||
} else {
|
||||
avatar = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22288%22%20height%3D%22225%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20288%20225%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_164edaf95ee%22%3E%3Crect%20width%3D%22288%22%20height%3D%22225%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2296.32500076293945%22%20y%3D%22118.8%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'
|
||||
}
|
||||
let banner
|
||||
if (team.profile.banner !== undefined && team.profile.banner !== 'a') {
|
||||
if (team.profile.banner !== undefined && team.profile.banner !== null) {
|
||||
banner = team.profile.banner
|
||||
} else {
|
||||
banner = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22288%22%20height%3D%22225%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20288%20225%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_164edaf95ee%22%3E%3Crect%20width%3D%22288%22%20height%3D%22225%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2296.32500076293945%22%20y%3D%22118.8%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'
|
||||
@@ -74,8 +74,8 @@ const TeamsDetails = ({ classes, team }) => {
|
||||
<CssBaseline />
|
||||
<main className={classes.layout}>
|
||||
<Paper className={classes.paper}>
|
||||
<Link to='/teams'>← Back to all teams</Link>
|
||||
<div className={classes.heroContent}>
|
||||
<Link to='/'>← Back to all teams</Link>
|
||||
<img src={banner} alt={team.name} className={classes.banner} />
|
||||
<img src={avatar} alt={team.name} className={classes.avatar} />
|
||||
<Typography
|
||||
|
||||
@@ -11,7 +11,7 @@ import Button from '@material-ui/core/Button'
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
// const TeamDetailsLink = ({ teamSlug, ...props }) => <Link to={`/teams/${teamSlug}`} {...props} />
|
||||
export const TeamsItem = ({ classes, team }) => {
|
||||
/* let avatar
|
||||
if (team.profile.avatar !== undefined && team.profile.avatar !== 'a') {
|
||||
@@ -50,7 +50,7 @@ export const TeamsItem = ({ classes, team }) => {
|
||||
</CardContent>
|
||||
</CardActionArea>
|
||||
<CardActions>
|
||||
<Link to={`/${team.slug}`}>
|
||||
<Link to={`/teams/${team.slug}`}>
|
||||
<Button size='small' color='primary' className={classes.buttonRight}>
|
||||
Details
|
||||
</Button>
|
||||
|
||||
@@ -102,6 +102,12 @@ export const TeamsList = ({ classes, match }) => (
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<Grid container spacing={40}>
|
||||
<MessageCard message='No teams found' />
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
|
||||
Generated
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "AATeamModule",
|
||||
"version": "2.0.1",
|
||||
"lockfileVersion": 1
|
||||
}
|
||||
Reference in new issue
Block a user