Merge pull request #8 from AdvancedAlgos/develop

Fix Images for Master App and move uploads to dev storage
This commit is contained in:
Barry Low authored and GitHub committed 2018-10-17 14:55:30 -07:00
commit aedf5e05e4
51 files changed
+2618 -184

No files matched your search

+1
View File
@@ -1,4 +1,5 @@
# Advanced Algos Team Module
[![npm client version](https://badge.fury.io/js/%40advancedalgos%2Fteams-client.svg)](https://badge.fury.io/js/%40advancedalgos%2Fteams-client)
## Introduction
+1
View File
@@ -13,6 +13,7 @@ const TEAMS_FRAGMENT = gql`{
createdAt
profile {
avatar
banner
description
motto
updatedAt
+6 -11
View File
@@ -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
}
}
}
-1
View File
@@ -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
+14 -22
View File
@@ -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
View File
@@ -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
}
}
`
-19
View File
@@ -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 -2
View File
@@ -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
}
}
+1 -1
View File
@@ -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
}
}
+1 -1
View File
@@ -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
View File
@@ -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)
+3
View File
@@ -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)
+11 -2
View File
@@ -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:&nbsp;
{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&rsquo;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&rsquo;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)
+28
View File
@@ -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)
+59
View File
@@ -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)
+30
View File
@@ -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'>&larr; Back to all teams</Link>
<div className={classes.heroContent}>
<Link to='/'>&larr; 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 (
+5
View File
@@ -0,0 +1,5 @@
{
"name": "AATeamModule",
"version": "2.0.1",
"lockfileVersion": 1
}