Merge pull request #70 from AdvancedAlgos/develop

Update Team Styles
This commit is contained in:
Barry Low authored and GitHub committed 2018-11-16 16:04:58 -08:00
commit 000e32278e
38 files changed
+2905 -1783

No files matched your search

+1 -1
View File
@@ -1,7 +1,7 @@
version: '3'
services:
prisma:
image: prismagraphql/prisma:1.15.1
image: prismagraphql/prisma:1.20
restart: always
ports:
- "4466:4466"
+977 -1481
View File
File diff suppressed because it is too large. Load diff
+12 -12
View File
@@ -7,31 +7,31 @@
"dev": "npm-run-all --parallel debug playground"
},
"dependencies": {
"@azure/storage-blob": "^10.0.0-preview",
"@babel/cli": "^7.1.2",
"@babel/core": "^7.1.2",
"@azure/storage-blob": "^10.1.0-preview",
"@babel/cli": "^7.1.5",
"@babel/core": "^7.1.5",
"@babel/node": "^7.0.0",
"@babel/polyfill": "^7.0.0",
"@babel/preset-env": "^7.1.0",
"@babel/preset-env": "^7.1.5",
"@babel/register": "^7.0.0",
"apollo-errors": "^1.9.0",
"apollo-server-express": "^2.1.0",
"apollo-server-express": "^2.2.2",
"axios": "^0.18.0",
"cors": "^2.8.4",
"cors": "^2.8.5",
"debug": "^4.1.0",
"dotenv": "^6.1.0",
"express": "^4.16.4",
"express-jwt": "^5.3.1",
"fast-xml-parser": "^3.12.5",
"fast-xml-parser": "^3.12.7",
"graphql-import": "^0.7.1",
"graphql-middleware": "^1.7.7",
"graphql-middleware": "^1.7.8",
"graphql-subscriptions": "^1.0.0",
"graphql-tag": "^2.10.0",
"graphql-tools": "^4.0.1",
"graphql-tools": "^4.0.3",
"jsonwebtoken": "^8.3.0",
"jwks-rsa": "^1.3.0",
"lodash.get": "^4.4.2",
"nodemon": "^1.18.4",
"nodemon": "^1.18.6",
"prisma-binding": "^2.1.6",
"request": "^2.88.0",
"request-promise-native": "^1.0.5",
@@ -40,9 +40,9 @@
"devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.1.0",
"@babel/plugin-proposal-throw-expressions": "^7.0.0",
"graphql-cli": "^2.16.5",
"graphql-cli": "^2.17.0",
"lodash.merge": "^4.6.1",
"npm-run-all": "4.1.3",
"prisma": "^1.18.1"
"prisma": "^1.20.1"
}
}
+63 -33
View File
@@ -1,5 +1,5 @@
# source: http://localhost:4466
# timestamp: Fri Oct 05 2018 13:16:40 GMT-0700 (Pacific Daylight Time)
# timestamp: Tue Nov 13 2018 13:35:00 GMT-0800 (PST)
type AggregateFBStatus {
count: Int!
@@ -147,15 +147,15 @@ input FBStatusSubscriptionWhereInput {
node: FBStatusWhereInput
}
input FBStatusUpdateInput {
status: Status
reason: String
}
input FBStatusUpdateManyInput {
create: [FBStatusCreateInput!]
}
input FBStatusUpdateManyMutationInput {
status: Status
reason: String
}
input FBStatusWhereInput {
"""Logical AND on all given filters."""
AND: [FBStatusWhereInput!]
@@ -252,7 +252,7 @@ type FinancialBeings implements Node {
name: String!
slug: String!
avatar: String
team(where: TeamWhereInput): Team
team: Team
status(where: FBStatusWhereInput, orderBy: FBStatusOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [FBStatus!]
updatedAt: DateTime!
createdAt: DateTime!
@@ -380,6 +380,14 @@ input FinancialBeingsUpdateInput {
status: FBStatusUpdateManyInput
}
input FinancialBeingsUpdateManyMutationInput {
type: FBType
kind: FBKind
name: String
slug: String
avatar: String
}
input FinancialBeingsUpdateManyWithoutTeamInput {
create: [FinancialBeingsCreateWithoutTeamInput!]
connect: [FinancialBeingsWhereUniqueInput!]
@@ -822,15 +830,15 @@ input MemberStatusSubscriptionWhereInput {
node: MemberStatusWhereInput
}
input MemberStatusUpdateInput {
status: Status
reason: String
}
input MemberStatusUpdateManyInput {
create: [MemberStatusCreateInput!]
}
input MemberStatusUpdateManyMutationInput {
status: Status
reason: String
}
input MemberStatusWhereInput {
"""Logical AND on all given filters."""
AND: [MemberStatusWhereInput!]
@@ -961,6 +969,12 @@ input MemberUpdateInput {
status: MemberStatusUpdateManyInput
}
input MemberUpdateManyMutationInput {
alias: String
authId: String
visible: Boolean
}
input MemberUpdateOneWithoutTeamsInput {
create: MemberCreateWithoutTeamsInput
connect: MemberWhereUniqueInput
@@ -1176,16 +1190,16 @@ type Mutation {
upsertMember(where: MemberWhereUniqueInput!, create: MemberCreateInput!, update: MemberUpdateInput!): Member!
upsertFinancialBeings(where: FinancialBeingsWhereUniqueInput!, create: FinancialBeingsCreateInput!, update: FinancialBeingsUpdateInput!): FinancialBeings!
upsertTeamMemberStatus(where: TeamMemberStatusWhereUniqueInput!, create: TeamMemberStatusCreateInput!, update: TeamMemberStatusUpdateInput!): TeamMemberStatus!
updateManyTeams(data: TeamUpdateInput!, where: TeamWhereInput): BatchPayload!
updateManyTeamMemberses(data: TeamMembersUpdateInput!, where: TeamMembersWhereInput): BatchPayload!
updateManyMembers(data: MemberUpdateInput!, where: MemberWhereInput): BatchPayload!
updateManyFinancialBeingses(data: FinancialBeingsUpdateInput!, where: FinancialBeingsWhereInput): BatchPayload!
updateManyTeamProfiles(data: TeamProfileUpdateInput!, where: TeamProfileWhereInput): BatchPayload!
updateManyWallets(data: WalletUpdateInput!, where: WalletWhereInput): BatchPayload!
updateManyMemberStatuses(data: MemberStatusUpdateInput!, where: MemberStatusWhereInput): BatchPayload!
updateManyFBStatuses(data: FBStatusUpdateInput!, where: FBStatusWhereInput): BatchPayload!
updateManyTeamMemberStatuses(data: TeamMemberStatusUpdateInput!, where: TeamMemberStatusWhereInput): BatchPayload!
updateManyTeamStatuses(data: TeamStatusUpdateInput!, where: TeamStatusWhereInput): BatchPayload!
updateManyTeams(data: TeamUpdateManyMutationInput!, where: TeamWhereInput): BatchPayload!
updateManyTeamMemberses(data: TeamMembersUpdateManyMutationInput!, where: TeamMembersWhereInput): BatchPayload!
updateManyMembers(data: MemberUpdateManyMutationInput!, where: MemberWhereInput): BatchPayload!
updateManyFinancialBeingses(data: FinancialBeingsUpdateManyMutationInput!, where: FinancialBeingsWhereInput): BatchPayload!
updateManyTeamProfiles(data: TeamProfileUpdateManyMutationInput!, where: TeamProfileWhereInput): BatchPayload!
updateManyWallets(data: WalletUpdateManyMutationInput!, where: WalletWhereInput): BatchPayload!
updateManyMemberStatuses(data: MemberStatusUpdateManyMutationInput!, where: MemberStatusWhereInput): BatchPayload!
updateManyFBStatuses(data: FBStatusUpdateManyMutationInput!, where: FBStatusWhereInput): BatchPayload!
updateManyTeamMemberStatuses(data: TeamMemberStatusUpdateManyMutationInput!, where: TeamMemberStatusWhereInput): BatchPayload!
updateManyTeamStatuses(data: TeamStatusUpdateManyMutationInput!, where: TeamStatusWhereInput): BatchPayload!
deleteManyTeams(where: TeamWhereInput): BatchPayload!
deleteManyTeamMemberses(where: TeamMembersWhereInput): BatchPayload!
deleteManyMembers(where: MemberWhereInput): BatchPayload!
@@ -1290,10 +1304,10 @@ type Team implements Node {
id: ID!
name: String!
slug: String!
profile(where: TeamProfileWhereInput): TeamProfile
profile: TeamProfile
members(where: TeamMembersWhereInput, orderBy: TeamMembersOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [TeamMembers!]
owner: String!
wallet(where: WalletWhereInput): Wallet
wallet: Wallet
fb(where: FinancialBeingsWhereInput, orderBy: FinancialBeingsOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [FinancialBeings!]
status(where: TeamStatusWhereInput, orderBy: TeamStatusOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [TeamStatus!]
createdAt: DateTime!
@@ -1361,8 +1375,8 @@ type TeamEdge {
type TeamMembers implements Node {
id: ID!
member(where: MemberWhereInput): Member
team(where: TeamWhereInput): Team
member: Member
team: Team
role: Role
status(where: TeamMemberStatusWhereInput, orderBy: TeamMemberStatusOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [TeamMemberStatus!]
email: String
@@ -1595,6 +1609,11 @@ input TeamMemberStatusUpdateManyInput {
upsert: [TeamMemberStatusUpsertWithWhereUniqueNestedInput!]
}
input TeamMemberStatusUpdateManyMutationInput {
status: Status
reason: String
}
input TeamMemberStatusUpdateWithWhereUniqueNestedInput {
where: TeamMemberStatusWhereUniqueInput!
data: TeamMemberStatusUpdateDataInput!
@@ -1741,6 +1760,11 @@ input TeamMembersUpdateInput {
status: TeamMemberStatusUpdateManyInput
}
input TeamMembersUpdateManyMutationInput {
role: Role
email: String
}
input TeamMembersUpdateManyWithoutMemberInput {
create: [TeamMembersCreateWithoutMemberInput!]
connect: [TeamMembersWhereUniqueInput!]
@@ -2084,7 +2108,7 @@ input TeamProfileUpdateDataInput {
banner: String
}
input TeamProfileUpdateInput {
input TeamProfileUpdateManyMutationInput {
description: String
motto: String
avatar: String
@@ -2411,15 +2435,15 @@ input TeamStatusSubscriptionWhereInput {
node: TeamStatusWhereInput
}
input TeamStatusUpdateInput {
status: Status
reason: String
}
input TeamStatusUpdateManyInput {
create: [TeamStatusCreateInput!]
}
input TeamStatusUpdateManyMutationInput {
status: Status
reason: String
}
input TeamStatusWhereInput {
"""Logical AND on all given filters."""
AND: [TeamStatusWhereInput!]
@@ -2553,6 +2577,12 @@ input TeamUpdateInput {
status: TeamStatusUpdateManyInput
}
input TeamUpdateManyMutationInput {
name: String
slug: String
owner: String
}
input TeamUpdateOneWithoutFbInput {
create: TeamCreateWithoutFbInput
connect: TeamWhereUniqueInput
@@ -2902,7 +2932,7 @@ input WalletUpdateDataInput {
balance: Float
}
input WalletUpdateInput {
input WalletUpdateManyMutationInput {
balance: Float
}
+2 -2
View File
@@ -60,7 +60,7 @@ export const resolvers = {
logger.info('createTeamUrl:')
logger.info(JSON.stringify(await createTeamUrl))
const platformUrl = 'https://develop.advancedalgos.net/AABrowserAPI/newTeam/'
const platformUrl = 'https://charts-dev.advancedalgos.net/AABrowserAPI/newTeam/'
// const platformUrl = 'http://localhost:1337/AABrowserAPI/teamSetup/'
logger.info(`${platformUrl}${createTeamUrl}/${authId}`)
@@ -152,7 +152,7 @@ export const resolvers = {
logger.info('deleteTeamUrl:')
logger.info(JSON.stringify(await deleteTeamUrl))
const platformUrl = 'https://develop.advancedalgos.net/AABrowserAPI/deleteTeam/'
const platformUrl = 'https://charts-dev.advancedalgos.net/AABrowserAPI/deleteTeam/'
// const platformUrl = 'http://localhost:1337/AABrowserAPI/teamSetup/'
logger.info(`${platformUrl}${deleteTeamUrl}/${authId}`)
+1 -1
View File
@@ -32,7 +32,7 @@ const db = new Prisma({
typeDefs: 'src/generated/prisma.graphql',
endpoint: process.env.PRISMA_ENDPOINT,
secret: process.env.PRISMA_SECRET,
debug: true
debug: false
})
const app = express()
+130 -29
View File
@@ -1,26 +1,27 @@
{
"name": "@advancedalgos/teams-client",
"version": "0.0.26",
"version": "0.0.27",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@advancedalgos/web-components": {
"version": "0.0.13",
"resolved": "https://registry.npmjs.org/@advancedalgos/web-components/-/web-components-0.0.13.tgz",
"integrity": "sha512-jXz2w/r08GX8uqB4UTDaow27T3juvR7Bk/80TWmDORVPNCPK152MEUBgxF161hAyOj1jdB+K4M1Fy5GkEpDhmw==",
"version": "0.0.15",
"resolved": "https://registry.npmjs.org/@advancedalgos/web-components/-/web-components-0.0.15.tgz",
"integrity": "sha512-Z9QyMqgpR/Al+0EYuLtSK3/9BJ/anB0zulBG7QMac9xCgNGSSbon9GndtSIFN3HwyirDCsIH3CZdPi6tJL3KnA==",
"requires": {
"@azure/storage-blob": "^10.1.0-preview",
"@material-ui/core": "^3.2.2",
"@material-ui/icons": "^3.0.1",
"apollo-client": "^2.4.2",
"apollo-client": "^2.4.5",
"blob-util": "^2.0.2",
"browser-image-resizer": "^1.2.0",
"graphql": "^14.0.2",
"graphql-tag": "^2.9.2",
"graphql-tag": "^2.10.0",
"prop-types": "^15.6.2",
"react-apollo": "^2.1.11",
"react": "^16.6.1",
"react-apollo": "^2.3.1",
"react-dom": "^16.6.1",
"react-dropzone": "^5.1.0",
"react-image-crop": "^5.0.0",
"react-image-cropper": "^1.3.0"
},
"dependencies": {
@@ -34,16 +35,76 @@
"tslib": "^1.9.3"
}
},
"@types/async": {
"version": "2.0.50",
"resolved": "https://registry.npmjs.org/@types/async/-/async-2.0.50.tgz",
"integrity": "sha512-VMhZMMQgV1zsR+lX/0IBfAk+8Eb7dPVMWiQGFAt3qjo5x7Ml6b77jUo0e1C3ToD+XRDXqtrfw+6AB0uUsPEr3Q==",
"optional": true
},
"@types/node": {
"version": "9.6.35",
"resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.35.tgz",
"integrity": "sha512-h5zvHS8wXHGa+Gcqs9K8vqCgOtqjr0+NqG/DDJmQIX1wpR9HivAfgV8bjcD3mGM4bPfQw5Aneb2Pn8355L83jA=="
"version": "9.6.39",
"resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.39.tgz",
"integrity": "sha512-c3OkjgNpSMdHan56WhklP0FMOk5ocilKz2Mpa0NOGzu8jw5YERjCf9FG0epYB1+TxScv/oI4uJ204u2mUg7Hcw=="
},
"apollo-cache": {
"version": "1.1.20",
"resolved": "https://registry.npmjs.org/apollo-cache/-/apollo-cache-1.1.20.tgz",
"integrity": "sha512-+Du0/4kUSuf5PjPx0+pvgMGV12ezbHA8/hubYuqRQoy/4AWb4faa61CgJNI6cKz2mhDd9m94VTNKTX11NntwkQ==",
"requires": {
"apollo-utilities": "^1.0.25"
}
},
"apollo-client": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/apollo-client/-/apollo-client-2.4.5.tgz",
"integrity": "sha512-nUm06EGa4TP/IY68OzmC3lTD32TqkjLOQdb69uYo+lHl8NnwebtrAw3qFtsQtTEz6ueBp/Z/HasNZng4jwafVQ==",
"requires": {
"@types/async": "2.0.50",
"@types/zen-observable": "^0.8.0",
"apollo-cache": "1.1.20",
"apollo-link": "^1.0.0",
"apollo-link-dedup": "^1.0.0",
"apollo-utilities": "1.0.25",
"symbol-observable": "^1.0.2",
"zen-observable": "^0.8.0"
}
},
"apollo-utilities": {
"version": "1.0.25",
"resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.0.25.tgz",
"integrity": "sha512-AXvqkhni3Ir1ffm4SA1QzXn8k8I5BBl4PVKEyak734i4jFdp+xgfUyi2VCqF64TJlFTA/B73TRDUvO2D+tKtZg==",
"requires": {
"fast-json-stable-stringify": "^2.0.0"
}
},
"events": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz",
"integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA=="
},
"fbjs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fbjs/-/fbjs-1.0.0.tgz",
"integrity": "sha512-MUgcMEJaFhCaF1QtWGnmq9ZDRAzECTCRAF7O6UZIlAlkTs1SasiX9aP0Iw7wfD2mJ7wDTNfg2w7u5fSCwJk1OA==",
"requires": {
"core-js": "^2.4.1",
"fbjs-css-vars": "^1.0.0",
"isomorphic-fetch": "^2.1.1",
"loose-envify": "^1.0.0",
"object-assign": "^4.1.0",
"promise": "^7.1.1",
"setimmediate": "^1.0.5",
"ua-parser-js": "^0.7.18"
}
},
"hoist-non-react-statics": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.1.0.tgz",
"integrity": "sha512-MYcYuROh7SBM69xHGqXEwQqDux34s9tz+sCnxJmN18kgWh6JFdTw/5YdZtqsOdZJXddE/wUpCzfEdDrJj8p0Iw==",
"requires": {
"react-is": "^16.3.2"
}
},
"ms-rest-js": {
"version": "0.22.425",
"resolved": "https://registry.npmjs.org/ms-rest-js/-/ms-rest-js-0.22.425.tgz",
@@ -61,6 +122,24 @@
"xml2js": "^0.4.19"
}
},
"react-apollo": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/react-apollo/-/react-apollo-2.3.1.tgz",
"integrity": "sha512-xPteQmCzMJT8wE4v0zq38E6JWLhrNcJENl66fP117lwzU2lZA+qoUDcizqKl0z2OY5b+KklmqnPPD+wcWAdy7w==",
"requires": {
"fbjs": "^1.0.0",
"hoist-non-react-statics": "^3.0.0",
"invariant": "^2.2.2",
"lodash.flowright": "^3.5.0",
"lodash.isequal": "^4.5.0",
"prop-types": "^15.6.0"
}
},
"symbol-observable": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
},
"tough-cookie": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
@@ -1993,11 +2072,12 @@
}
},
"@material-ui/core": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-3.2.2.tgz",
"integrity": "sha512-wDTJyR76+OBdlltiPs3lc1gD6zR+dSA6nITtgkBeLf1NvWfNotMWdvldIDnF3bu24ySAX9imfzDfkBu4Edtqww==",
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-3.5.1.tgz",
"integrity": "sha512-yMBwYV5HQ/kZjncSmzHSx4uxJCePdbq9N58Jl0tq9D1gD5fKVJY/lItnQLRlcpCzZUkGxfDhpDutvLDq58ZAkg==",
"requires": {
"@babel/runtime": "7.1.2",
"@material-ui/utils": "^3.0.0-alpha.0",
"@types/jss": "^9.5.6",
"@types/react-transition-group": "^2.0.8",
"brcast": "^3.0.1",
@@ -2006,7 +2086,7 @@
"debounce": "^1.1.0",
"deepmerge": "^2.0.1",
"dom-helpers": "^3.2.1",
"hoist-non-react-statics": "^2.5.0",
"hoist-non-react-statics": "^3.0.0",
"is-plain-object": "^2.0.4",
"jss": "^9.3.3",
"jss-camel-case": "^6.0.0",
@@ -2032,6 +2112,14 @@
"requires": {
"regenerator-runtime": "^0.12.0"
}
},
"hoist-non-react-statics": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.1.0.tgz",
"integrity": "sha512-MYcYuROh7SBM69xHGqXEwQqDux34s9tz+sCnxJmN18kgWh6JFdTw/5YdZtqsOdZJXddE/wUpCzfEdDrJj8p0Iw==",
"requires": {
"react-is": "^16.3.2"
}
}
}
},
@@ -2083,6 +2171,24 @@
}
}
},
"@material-ui/utils": {
"version": "3.0.0-alpha.0",
"resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-3.0.0-alpha.0.tgz",
"integrity": "sha512-HwC/pBcPG81UP4Jh0BaH2i4wAY9aDOrvL5+B/7J6cyFlG/Wip5Li+qI+GDlk9MR3kpG8v0sxfpWA0IlQYcHK6g==",
"requires": {
"@babel/runtime": "7.1.2"
},
"dependencies": {
"@babel/runtime": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.1.2.tgz",
"integrity": "sha512-Y3SCjmhSupzFB6wcv1KmmFucH6gDVnI30WjOcicV10ju0cZjak3Jcs67YLIXBrmZYw1xCrVeJPbycFwrqNyxpg==",
"requires": {
"regenerator-runtime": "^0.12.0"
}
}
}
},
"@sheerun/eslint-config-standard": {
"version": "10.2.1",
"resolved": "https://registry.npmjs.org/@sheerun/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz",
@@ -2219,9 +2325,9 @@
"integrity": "sha512-HtKGu+qG1NPvYe1z7ezLsyIaXYyi8SoAVqWDZgDQ8dLrsZvSzUNCwZyfX33uhWxL/SU0ZDQZ3nwZ0nimt507Kw=="
},
"@types/react": {
"version": "16.4.18",
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.4.18.tgz",
"integrity": "sha512-eFzJKEg6pdeaukVLVZ8Xb79CTl/ysX+ExmOfAAqcFlCCK5TgFDD9kWR0S18sglQ3EmM8U+80enjUqbfnUyqpdA==",
"version": "16.7.6",
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.7.6.tgz",
"integrity": "sha512-QBUfzftr/8eg/q3ZRgf/GaDP6rTYc7ZNem+g4oZM38C9vXyV8AWRWaTQuW5yCoZTsfHrN7b3DeEiUnqH9SrnpA==",
"requires": {
"@types/prop-types": "*",
"csstype": "^2.2.0"
@@ -6815,9 +6921,9 @@
}
},
"flatmap-stream": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/flatmap-stream/-/flatmap-stream-0.1.1.tgz",
"integrity": "sha512-lAq4tLbm3sidmdCN8G3ExaxH7cUCtP5mgDvrYowsx84dcYkJJ4I28N7gkxA6+YlSXzaGLJYIDEi9WGfXzMiXdw=="
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/flatmap-stream/-/flatmap-stream-0.1.2.tgz",
"integrity": "sha512-ucyr6WkLXjyMuHPtOUq4l+nSAxgWi7v4QO508eQ9resnGj+lSup26oIsUI5aH8k4Qfpjsxa8dDf9UCKkS2KHzQ=="
},
"flatten": {
"version": "1.0.2",
@@ -10920,9 +11026,9 @@
"dev": true
},
"popper.js": {
"version": "1.14.4",
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.4.tgz",
"integrity": "sha1-juwdj/AqWjoVLdQ0FKFce3n9abY="
"version": "1.14.5",
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.5.tgz",
"integrity": "sha512-fs4Sd8bZLgEzrk8aS7Em1qh+wcawtE87kRUJQhK6+LndyV1HerX7+LURzAylVaTyWIn5NTB/lyjnWqw/AZ6Yrw=="
},
"posix-character-classes": {
"version": "0.1.1",
@@ -12132,11 +12238,6 @@
"shallowequal": "^1.0.2"
}
},
"react-image-crop": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/react-image-crop/-/react-image-crop-5.0.0.tgz",
"integrity": "sha512-MBT18tcHeEpmrhbSS6hx00MmfNgrnlhZuwY96cGRPhUmNeabxM7UBCcoU+oJCZXB0iGZk38zy/YGoZ4ELVp/LQ=="
},
"react-image-cropper": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/react-image-cropper/-/react-image-cropper-1.3.0.tgz",
+1 -1
View File
@@ -69,7 +69,7 @@
"workbox-cli": "^3.6.2"
},
"dependencies": {
"@advancedalgos/web-components": "0.0.13",
"@advancedalgos/web-components": "0.0.15",
"@azure/storage-blob": "^10.0.0-preview",
"apollo-cache-inmemory": "^1.3.5",
"apollo-client": "^2.4.2",
+7 -8
View File
@@ -8,7 +8,6 @@ import {
AcceptTeamInvite,
ManageTeams,
TeamMembers,
FinancialBeings,
Settings,
Teams,
Landing,
@@ -45,6 +44,11 @@ class App extends Component {
path={`/teams/manage-teams`}
render={props => <ManageTeams {...props} auth={this.props.auth} />}
/>
<Route
exact
path={`/teams/manage-teams/:slug`}
render={props => <ManageTeams {...props} auth={this.props.auth} user={this.state.user} />}
/>
<Route
exact
path={`/teams/team-members`}
@@ -52,12 +56,7 @@ class App extends Component {
/>
<Route
exact
path={`/teams/financial-beings`}
render={props => <FinancialBeings {...props} auth={this.props.auth} />}
/>
<Route
exact
path={`/teams/financial-beings`}
path={`/teams/settings`}
render={props => <Settings {...props} auth={this.props.auth} />}
/>
<Route
@@ -65,7 +64,7 @@ class App extends Component {
path={`/teams/activate-team-membership`}
render={props => <AcceptTeamInvite {...props} auth={this.props.auth} />}
/>
<Route path='/teams/:slug' component={Teams} />
<Route exact path='/teams/:slug' component={Teams} />
</Switch>
</div>
)
@@ -120,7 +120,7 @@ export class ManageFBEdit extends Component {
let avatar = null
if (fb.avatar !== undefined && fb.avatar !== null) avatar = fb.avatar
if (this.state.avatar !== null) avatar = this.state.avatar
if (this.state.avatar === null && fb.avatar === undefined) avatar = 'https://algobotcommstorage.blob.core.windows.net/aateammodule/aa-avatar-default.png'
if (this.state.avatar === null && fb.avatar === undefined) avatar = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-avatar-default.png'
if (loading || data === undefined) {
return (<MessageCard message='Loading...' />)
@@ -18,7 +18,7 @@ export const ManageFBItem = ({ classes, team, authId }) => {
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'
avatar = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-avatar-default.png'
}
return (
<Grid item xs={12}>
@@ -32,7 +32,7 @@ export const ManageMembersItem = ({ classes, member, teamId, authId }) => {
</Typography>
</Grid>
<Grid item xs={4}>
<Typography color='textSecondary' variant='body2' component='h4' align='left' >
<Typography color='textSecondary' variant='body1' component='h4' align='left' >
{email !== null ? `${memberStatus[memberStatus.length - 1].status} | Sent: ${memberStatus[memberStatus.length - 1].createdAt}` : `${member.role} | Member since: `}
</Typography>
</Grid>
@@ -63,7 +63,7 @@ export const ManageMembersTeamItem = ({ classes, team, authId }) => {
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'
avatar = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-avatar-default.png'
}
if (team.members.length > 0) {
return (
@@ -72,12 +72,12 @@ export class ManageTeamDetails extends Component {
if (profile.avatar !== undefined && profile.avatar !== null) {
avatar = profile.avatar
} else {
avatar = 'https://algobotcommstorage.blob.core.windows.net/aateammodule/aa-avatar-default.png'
avatar = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/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'
banner = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-banner-default.png'
}
return (
<div>
@@ -129,11 +129,11 @@ export class ManageTeamEdit extends Component {
let avatar = null
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
if (this.state.avatar === null && team.profile !== null && team.profile.avatar === undefined) avatar = 'https://algobotcommstorage.blob.core.windows.net/aateammodule/aa-avatar-default.png'
if (this.state.avatar === null && team.profile !== null && team.profile.avatar === undefined) avatar = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-avatar-default.png'
let banner = null
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
if (this.state.banner === null && team.profile !== null && team.profile.banner === undefined) banner = 'https://algobotcommstorage.blob.core.windows.net/aateammodule/aa-banner-default.png'
if (this.state.banner === null && team.profile !== null && team.profile.banner === undefined) banner = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-banner-default.png'
log.debug('team images: ', avatar, banner)
if (loading || data === undefined) {
@@ -20,7 +20,7 @@ export const ManageTeamsItem = ({ classes, team, authId }) => {
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'
avatar = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-avatar-default.png'
}
return (
<Grid item xs={12}>
@@ -18,7 +18,7 @@ export const ManageFBItem = ({ classes, team }) => {
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'
avatar = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-avatar-default.png'
}
return (
<Grid item xs={12}>
@@ -15,10 +15,13 @@ import log from '../../../utils/log'
import ManageFBItem from './ManageFBItem'
const styles = theme => ({
root: {
flexGrow: 1
},
heroContent: {
maxWidth: 600,
margin: '0 auto',
padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px`
maxWidth: 800,
margin: `${theme.spacing.unit * 4}px auto`,
padding: 0
},
cardGrid: {
padding: `${theme.spacing.unit * 8}px 0`
@@ -63,17 +66,21 @@ export const ManageFBList = ({ classes }) => (
if (!loading && !error) {
if (data.teams_TeamsByOwner.length > 0) {
return (
<Grid container spacing={0} direction='column' justify='center' alignItems='center'>
{!loading &&
data.teams_TeamsByOwner.map(team => (
<ManageFBItem
key={team.id}
team={team}
classes={classes}
/>
))}
{errors}
</Grid>
<div className={classes.root}>
<div className={classes.heroContent}>
<Grid container spacing={8} direction='column' alignItems='stretch'>
{!loading &&
data.teams_TeamsByOwner.map(team => (
<ManageFBItem
key={team.id}
team={team}
classes={classes}
/>
))}
{errors}
</Grid>
</div>
</div>
)
} else {
return (
@@ -83,7 +90,7 @@ export const ManageFBList = ({ classes }) => (
<Typography variant='h5' align='center'>
You don&rsquo;t have any financial being. To create one, create a team first!
</Typography>
<Typography variant='body2' align='center' gutterBottom>
<Typography variant='body1' align='center' gutterBottom>
After you create a team, a default trading algobot will be cloned and added to your team so
that you can begin experimenting right away.
</Typography>
+27 -2
View File
@@ -1,6 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
import Typography from '@material-ui/core/Typography'
import { withStyles } from '@material-ui/core/styles'
import { BannerTopBar } from '../common'
@@ -21,9 +22,33 @@ const styles = theme => ({
})
const Landing = ({ classes, ...props }) => (
<div>
<React.Fragment>
<BannerTopBar size='big' title='Teams Module' text='Discover, create and manage Advanced Algos teams.' backgroundUrl='https://advancedalgos.net/img/photos/teams.jpg' />
</div>
<div className='homePage container'>
<Typography variant='h1' align='center' className='title'>
Welcome to the Teams Module!
</Typography>
<Typography variant='h2' align='center' className='subtitle'>
Multidisciplinary groups of humans joining forces to breed financial beings and compete.
</Typography>
<div className='column'>
<Typography align='justify'>
One of the core propositions of Advanced Algos revolves around people teaming up to breed financial beings and compete in algorithmic trading competitions. Both developing and competing are team activities.
</Typography>
<Typography align='justify'>
If you are a user of the system but still haven’t joined any teams, the Teams Module is the right place to find one or even create your own.
</Typography>
</div>
<div className='column'>
<Typography align='justify'>
You may join and participate in as many teams as you wish.
</Typography>
<Typography align='justify'>
When you create your own team, you become the team’s owner and may allow more people in the team at your sole discretion. It has been shown that larger teams tend to become more intelligent.
</Typography>
</div>
</div>
</React.Fragment>
)
Landing.propTypes = {
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types'
import { Mutation } from 'react-apollo'
import { withStyles } from '@material-ui/core/styles'
import Grid from '@material-ui/core/Grid'
import Button from '@material-ui/core/Button'
import AddIcon from '@material-ui/icons/Add'
import TextField from '@material-ui/core/TextField'
@@ -34,14 +35,8 @@ const styles = theme => ({
marginLeft: '20%',
marginBottom: 10
},
buttonRight: {
// position: 'absolute',
// right: '3em'
marginTop: '1em',
marginRight: 'auto',
marginLeft: 'auto',
display: 'block',
lineHeight: '1em'
buttonFab: {
backgroundColor: '#CCCCCC'
}
})
@@ -93,12 +88,12 @@ export class CreateTeamDialog extends Component {
})
}
return (
<div>
<Grid container justify='center'>
<Button
variant='fab'
color='primary'
aria-label='Add'
className={classes.buttonRight}
className={classes.buttonFab}
onClick={this.handleClickOpen}
>
<AddIcon />
@@ -172,7 +167,7 @@ export class CreateTeamDialog extends Component {
</DialogActions>
</div>
</Dialog>
</div>
</Grid>
)
}}
</Mutation>
@@ -0,0 +1,180 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Paper from '@material-ui/core/Paper'
import Grid from '@material-ui/core/Grid'
import Button from '@material-ui/core/Button'
import { withStyles } from '@material-ui/core/styles'
import { Link } from 'react-router-dom'
import ManageTeamProfileView from './ManageTeamProfileView'
import ManageTeamProfileEdit from './ManageTeamProfileEdit'
import log from '../../../utils/log'
const styles = theme => ({
root: {
flexGrow: 1
},
'@global': {
body: {
backgroundColor: theme.palette.common.white
}
},
layout: {
width: 'auto',
marginLeft: theme.spacing.unit * 3,
marginRight: theme.spacing.unit * 3,
marginBottom: theme.spacing.unit * 6,
[theme.breakpoints.up(800 + theme.spacing.unit * 3 * 2)]: {
width: 800,
marginLeft: 'auto',
marginRight: 'auto'
}
},
paper: {
marginTop: 0,
marginBottom: theme.spacing.unit * 1,
padding: 0,
[theme.breakpoints.up(800 + theme.spacing.unit * 3 * 2)]: {
marginTop: theme.spacing.unit * 3,
marginBottom: theme.spacing.unit * 2,
padding: `0 0 ${theme.spacing.unit * 2}px`
}
},
heroContent: {
maxWidth: 800,
margin: '0 auto',
padding: 0
},
teamContent: {
margin: `${theme.spacing.unit * 1}px ${theme.spacing.unit * 3}px 0 0`
},
banner: {
maxWidth: '100%',
height: 'auto'
},
avatar: {
maxWidth: 100,
height: 100,
margin: `${theme.spacing.unit * 1}px 0 0 ${theme.spacing.unit * 3}px `
},
profileButtons: {
width: '90%',
margin: `${theme.spacing.unit * 3}px auto 0`,
padding: `${theme.spacing.unit * 2}px ${theme.spacing.unit * 2}px 0`,
borderTop: '1px solid #CCCCCC'
}
})
export class ManageTeamProfile extends Component {
constructor (props) {
super(props)
this.toggleEdit = this.toggleEdit.bind(this)
this.handleSave = this.handleSave.bind(this)
this.handleUpdate = this.handleUpdate.bind(this)
this.state = {
edit: false,
save: false
}
}
render () {
const { classes, team, slug, match } = this.props
log.debug('ManageTeamProfile render', this.state)
return (
<div className='container'>
<main className={classes.layout}>
<Paper className={classes.paper}>
<div className={classes.heroContent}>
{!this.state.edit && <ManageTeamProfileView team={team} />}
{this.state.edit &&
<ManageTeamProfileEdit
team={team}
slug={slug}
match={match}
save={this.state.save}
handleUpdate={this.handleUpdate}
/>
}
<Grid container justify='flex-end' direction='row' spacing={24} className={classes.profileButtons}>
{!this.state.edit &&
<React.Fragment>
<Grid item>
<Button
component={Link}
to='/teams/manage-teams'
color='primary'
variant='contained'
>
Back to all teams
</Button>
</Grid>
<Grid item>
<Button
onClick={e => this.toggleEdit()}
color='secondary'
variant='contained'
>
Edit Profile
</Button>
</Grid>
</React.Fragment>
}
{this.state.edit &&
<React.Fragment>
<Grid item>
<Button
onClick={e => this.toggleEdit()}
variant='contained'
color='primary'
>
Cancel
</Button>
</Grid>
<Grid item>
<Button
onClick={e => this.handleSave(e)}
variant='contained'
color='secondary'
>
Save Changes
</Button>
</Grid>
</React.Fragment>
}
</Grid>
</div>
</Paper>
</main>
</div>
)
}
toggleEdit () {
this.setState({ edit: !this.state.edit })
}
handleSave (e) {
e.preventDefault()
log.debug('handleSave')
this.setState({ save: true })
}
handleUpdate () {
log.debug('handleUpdate')
this.setState({ edit: false, save: false })
}
}
ManageTeamProfile.propTypes = {
classes: PropTypes.object.isRequired,
team: PropTypes.object.isRequired,
match: PropTypes.object.isRequired,
slug: PropTypes.string.isRequired
}
export default withStyles(styles)(ManageTeamProfile)
@@ -0,0 +1,376 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { Mutation } from 'react-apollo'
import { withStyles } from '@material-ui/core/styles'
import Grid from '@material-ui/core/Grid'
import TextField from '@material-ui/core/TextField'
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'
import log from '../../../utils/log'
const styles = theme => ({
root: {
flexGrow: 1
},
'@global': {
body: {
backgroundColor: theme.palette.common.white
}
},
layout: {
width: '100%',
marginBottom: theme.spacing.unit * 6,
[theme.breakpoints.up(800 + theme.spacing.unit * 3 * 2)]: {
width: 800,
marginLeft: 'auto',
marginRight: 'auto'
}
},
paper: {
marginTop: 0,
marginBottom: theme.spacing.unit * 3,
padding: 0,
[theme.breakpoints.up(800 + theme.spacing.unit * 3 * 2)]: {
marginTop: theme.spacing.unit * 3,
marginBottom: theme.spacing.unit * 6,
padding: `0 0 ${theme.spacing.unit * 2}px`
}
},
heroContent: {
maxWidth: 800,
margin: '0 auto',
padding: `0 0 ${theme.spacing.unit * 2}px`
},
editContentContainer: {
marginBottom: `${theme.spacing.unit * 3}px`
},
metaContainer: {
marginTop: `${theme.spacing.unit * 1}px`,
alignSelf: 'stretch',
borderRight: '1px solid #CCCCCC'
},
teamMeta: {
margin: `${theme.spacing.unit * 3}px 0 0`,
paddingLeft: `${theme.spacing.unit * 2}px`,
textAlign: 'center',
height: '100%'
},
teamContent: {
'& h2': {
padding: `${theme.spacing.unit * 4}px ${theme.spacing.unit * 3}px 0`
},
'& h4': {
padding: `0 ${theme.spacing.unit * 3}px 0`
},
'& h6': {
padding: `0 ${theme.spacing.unit * 3}px 0`
}
},
editInput: {
padding: `0 ${theme.spacing.unit * 3}px ${theme.spacing.unit * 2}px`,
'& label': {
display: 'none',
padding: `0 ${theme.spacing.unit * 4}px 0`
}
},
banner: {
maxWidth: '100%',
height: 'auto',
width: '100%'
},
avatar: {
maxWidth: 125,
height: 125,
margin: `0 auto ${theme.spacing.unit * 2}px`,
verticalAlign: 'middle',
borderRadius: '50%'
}
})
export class ManageTeamProfileEdit 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)
this.startSave = this.startSave.bind(this)
log.debug('ManageTeamProfileEdit constructor', 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.state = {
open: false,
motto: motto,
description: description,
avatar: avatar,
banner: banner,
save: false
}
}
render () {
const { classes, team, match, save, handleUpdate } = this.props
log.debug('ManageTeamProfileEdit render', this.props, this.props.slug, this.props.team, match)
const created = new Date(team.createdAt)
return (
<Mutation
mutation={UPDATE_TEAM_PROFILE}
refetchQueries={[
{
query: GET_TEAMS_BY_OWNER
}
]}
>
{(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://aadevelop.blob.core.windows.net/module-teams/module-default/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://aadevelop.blob.core.windows.net/module-teams/module-default/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
log.debug('team images: ', avatar, banner)
log.debug('saving profile status: ', save)
if (save && !this.state.save) {
log.debug('saving profile: ', save)
this.startSave(updateTeamProfile, team.slug, handleUpdate)
}
let errors
let loader
if (loading) {
loader = (
<Typography variant='caption'>Updating profile...</Typography>
)
}
if (error) {
errors = error.graphQLErrors.map(({ message }, i) => {
const displayMessage = checkGraphQLError(message)
log.debug('updateTeamProfile error:', displayMessage)
return (
<Typography key={i} variant='caption'>
{message}
</Typography>
)
})
}
return (
<React.Fragment>
<ImageUpload
key='banner'
handleUrl={this.handleBanner}
fileName={`${team.slug}-banner.jpg`}
containerName={containerName}
existingImage={banner}
imagePreviewConfig={{
width: '800px',
height: '200px',
title: 'Change Banner',
fontSize: '1.5em'
}}
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'
}}
containerStyle={{
display: 'block',
margin: 0,
height: '200px',
width: '800px',
overflow: 'visible'
}}
AzureStorageUrl={AzureStorageUrl}
AzureSASURL={AzureStorageSAS}
cropRatio={4}
/>
<Grid container className={classes.editContentContainer}>
<Grid item md={3} className={classes.metaContainer}>
<Grid container className={classes.teamMeta} direction='column' justify='flex-start'>
<Grid item>
<ImageUpload
key='avatar1'
handleUrl={this.handleAvatar}
fileName={`${team.slug}-avatar.jpg`}
containerName={containerName}
existingImage={avatar}
imagePreviewConfig={{
width: '125px',
height: '125px',
title: 'Change Avatar',
fontSize: '1.5em'
}}
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'
}}
containerStyle={{
display: 'block',
margin: '0 auto 12px',
height: '125px',
width: '125px',
overflow: 'visible'
}}
dropzoneStyle={{ height: '125px' }}
AzureStorageUrl={AzureStorageUrl}
AzureSASURL={AzureStorageSAS}
cropRatio={1}
/>
</Grid>
<Typography variant='subtitle1' paragraph gutterBottom>
Members: {team.members.length}
</Typography>
<Typography variant='subtitle1' paragraph gutterBottom>
Financial Beings: 1
</Typography>
<Typography variant='subtitle1' paragraph gutterBottom>
Created: {created.toLocaleDateString()}
</Typography>
</Grid>
</Grid>
<Grid item md={9}>
<Grid container className={classes.teamContent} direction='column'>
<Typography
variant='h2'
color='textPrimary'
gutterBottom
>
{team.name}
</Typography>
<Typography
variant='h4'
color='textSecondary'
>
Motto:
</Typography>
<TextField
autoFocus
margin='dense'
id='motto'
type='text'
fullWidth
value={this.state.motto}
onChange={this.handleChange}
className={classes.editInput}
/>
<Typography variant='h6' color='textPrimary'>
Description:
</Typography>
<TextField
margin='dense'
id='description'
type='text'
rows={4}
multiline
fullWidth
value={this.state.description}
onChange={this.handleChange}
className={classes.editInput}
/>
<Typography variant='h6' color='secondary'>
{loader}
{errors}
</Typography>
</Grid>
</Grid>
</Grid>
</React.Fragment>
)
}}
</Mutation>
)
}
handleClickOpen () {
this.setState({ open: true })
}
handleClose () {
this.setState({ open: false })
}
handleChange (e) {
log.debug('handleChange: ', e.target.id, e.target.value)
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) {
log.debug('handleAvatar: ', avatarUrl)
this.setState({ avatar: `${avatarUrl}?${Math.random()}` })
}
handleBanner (bannerUrl) {
log.debug('handleBanner: ', bannerUrl)
this.setState({ banner: `${bannerUrl}?${Math.random()}` })
}
startSave (updateTeamProfile, slug, handleUpdate) {
this.setState({ save: 'done' })
this.handleSubmit(updateTeamProfile, slug, handleUpdate)
}
async handleSubmit (updateTeamProfile, slug, handleUpdate) {
log.debug('updateTeamProfile, handleSubmit: ', this.state)
await updateTeamProfile({
variables: {
slug,
owner: this.authId,
description: this.state.description,
motto: this.state.motto,
avatar: this.state.avatar,
banner: this.state.banner
}
})
window.canvasApp.eventHandler.raiseEvent('User Profile Changed')
handleUpdate()
}
}
ManageTeamProfileEdit.propTypes = {
classes: PropTypes.object.isRequired,
slug: PropTypes.string.isRequired,
team: PropTypes.object,
match: PropTypes.object,
save: PropTypes.bool,
handleUpdate: PropTypes.func
}
export default withStyles(styles)(ManageTeamProfileEdit)
@@ -0,0 +1,207 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { Mutation } from 'react-apollo'
import { withStyles } from '@material-ui/core/styles'
import Grid from '@material-ui/core/Grid'
import Button from '@material-ui/core/Button'
import EditIcon from '@material-ui/icons/Edit'
import Dialog from '@material-ui/core/Dialog'
import DialogContent from '@material-ui/core/DialogContent'
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'
import log from '../../../utils/log'
const styles = theme => ({
dialogTitle: {
textAlign: 'center',
paddingBottom: `${theme.spacing.unit * 2}px`
},
buttonRight: {
justifyContent: 'flex-end'
}
})
export class ManageTeamProfileFBEdit 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.state = {
open: false,
avatar: avatar
}
}
render () {
log.debug('ManageTeamProfileFBEdit ', 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
}
]}
>
{(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://aadevelop.blob.core.windows.net/module-teams/module-default/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'>Updating avatar...</Typography>
)
}
if (error) {
errors = error.graphQLErrors.map(({ message }, i) => {
const displayMessage = checkGraphQLError(message)
log.debug('updateTeamProfile error:', displayMessage)
return (
<Typography key={i} variant='caption'>
{message}
</Typography>
)
})
}
log.debug('ManageTeamProfileFBEdit mutation:', classes)
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'
>
<DialogContent>
<Grid container justify='center' direction='column'>
<Grid item className={classes.dialogTitle}>
<Typography variant='h4'>
Edit Financial Being
</Typography>
</Grid>
<ImageUpload
key='avatar'
handleUrl={this.handleAvatar}
fileName={`${fb.slug}-fb-avatar.jpg`}
containerName={containerName}
existingImage={avatar}
imagePreviewConfig={{
width: '125px',
height: '125px',
title: 'Change FB Avatar',
fontSize: '1.5em'
}}
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'
}}
containerStyle={{
display: 'block',
margin: '0 auto 3em',
height: '125px',
width: '125px',
overflow: 'visible'
}}
dropzoneStyle={{ height: '125px' }}
AzureStorageUrl={AzureStorageUrl}
AzureSASURL={AzureStorageSAS}
cropRatio={1}
debug
/>
{loader}
{errors}
<Grid container justify='center' alignItems='center' direction='column'>
<Button
onClick={e => {
this.handleSubmit(e, updateFB, fb.id, slug)
}}
color='secondary'
variant='contained'
size='small'
>
Update Financial Being
</Button>
<Button onClick={this.handleClose} color='primary'>
Cancel
</Button>
</Grid>
</Grid>
</DialogContent>
</Dialog>
</div>
)
}}
</Mutation>
)
}
handleClickOpen () {
this.setState({ open: true })
}
handleClose () {
this.setState({ open: false })
}
handleAvatar (avatarUrl) {
log.debug('handleAvatar: ', avatarUrl)
this.setState({ avatar: `${avatarUrl}?${Math.random()}` })
}
async handleSubmit (e, updateFB, fbId, slug) {
log.debug('handleSubmit: ', this.state)
e.preventDefault()
await updateFB({
variables: {
fbId,
avatar: this.state.avatar
}
})
window.canvasApp.eventHandler.raiseEvent('User Profile Changed')
this.setState({ open: false })
}
}
ManageTeamProfileFBEdit.propTypes = {
classes: PropTypes.object.isRequired,
slug: PropTypes.string.isRequired,
fb: PropTypes.object
}
export default withStyles(styles)(ManageTeamProfileFBEdit)
@@ -0,0 +1,76 @@
import React from 'react'
import PropTypes from 'prop-types'
import Grid from '@material-ui/core/Grid'
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'
import Typography from '@material-ui/core/Typography'
import { withStyles } from '@material-ui/core/styles'
import ManageTeamProfileFBEdit from './ManageTeamProfileFBEdit'
import log from '../../../utils/log'
const styles = theme => ({
fbContainer: {
margin: `0 0 ${theme.spacing.unit * 2}px`
},
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 ManageTeamProvileFBView = ({ classes, team }) => {
log.debug('ManageTeamProvileFBView', team, team.fb[0], team.fb[0].avatar)
let avatar = (team.fb[0].avatar !== undefined && team.fb[0].avatar !== null) ? team.fb[0].avatar : 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-avatar-default.png'
return (
<Grid item xs={12} className={classes.fbContainer}>
<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>
<ManageTeamProfileFBEdit slug={team.slug} fb={team.fb[0]} />
</CardActions>
</div>
</Card>
</Grid>
)
}
ManageTeamProvileFBView.propTypes = {
classes: PropTypes.object.isRequired,
team: PropTypes.object.isRequired
}
export default withStyles(styles)(ManageTeamProvileFBView)
@@ -0,0 +1,155 @@
import React from 'react'
import PropTypes from 'prop-types'
import Typography from '@material-ui/core/Typography'
import Grid from '@material-ui/core/Grid'
import { withStyles } from '@material-ui/core/styles'
import ManageTeamProfileFBView from './ManageTeamProfileFBView'
const styles = theme => ({
root: {
flexGrow: 1
},
'@global': {
body: {
backgroundColor: theme.palette.common.white
}
},
layout: {
width: '100%',
marginBottom: theme.spacing.unit * 6,
[theme.breakpoints.up(800 + theme.spacing.unit * 3 * 2)]: {
width: 800,
marginLeft: 'auto',
marginRight: 'auto'
}
},
paper: {
marginTop: 0,
marginBottom: theme.spacing.unit * 3,
padding: 0,
[theme.breakpoints.up(800 + theme.spacing.unit * 3 * 2)]: {
marginTop: theme.spacing.unit * 3,
marginBottom: theme.spacing.unit * 6,
padding: `0 0 ${theme.spacing.unit * 2}px`
}
},
heroContent: {
maxWidth: 800,
margin: '0 auto',
padding: `0 0 ${theme.spacing.unit * 2}px`
},
metaContainer: {
marginTop: `${theme.spacing.unit * 1}px`,
alignSelf: 'stretch',
borderRight: '1px solid #CCCCCC'
},
teamMeta: {
margin: `${theme.spacing.unit * 3}px 0 0`,
paddingLeft: `${theme.spacing.unit * 2}px`,
textAlign: 'center'
},
teamContent: {
'& h2': {
padding: `${theme.spacing.unit * 4}px ${theme.spacing.unit * 3}px 0`
},
'& h4': {
padding: `0 ${theme.spacing.unit * 3}px ${theme.spacing.unit * 1}px`
},
'& h6': {
padding: `0 ${theme.spacing.unit * 3}px 0`
}
},
fbContent: {
borderTop: '1px solid #CCCCCC',
width: '90%',
margin: `${theme.spacing.unit * 3}px auto`,
paddingTop: `${theme.spacing.unit * 3}px`
},
banner: {
maxWidth: '100%',
height: 'auto',
width: '100%'
},
avatar: {
maxWidth: 125,
height: 125,
margin: `0 auto ${theme.spacing.unit * 2}px`,
verticalAlign: 'middle',
borderRadius: '50%'
},
backLink: {
display: 'block',
textDecoration: 'none',
margin: `${theme.spacing.unit * 3}px 0 0`,
color: theme.palette.secondary.main
}
})
const ManageTeamProfileView = ({ classes, team }) => {
let avatar = team.profile.avatar || 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-avatar-default.png'
let banner = team.profile.banner || 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-banner-default.png'
const created = new Date(team.createdAt)
return (
<React.Fragment>
<img src={banner} alt={team.name} className={classes.banner} />
<Grid container>
<Grid item md={3} className={classes.metaContainer}>
<Grid container className={classes.teamMeta} direction='column' justify='center'>
<img src={avatar} alt={team.name} className={classes.avatar} />
<Typography variant='subtitle1' paragraph gutterBottom>
Members: {team.members.length}
</Typography>
<Typography variant='subtitle1' paragraph gutterBottom>
Financial Beings: 1
</Typography>
<Typography variant='subtitle1' paragraph gutterBottom>
Created: {created.toLocaleDateString()}
</Typography>
</Grid>
</Grid>
<Grid item md={9}>
<Grid container className={classes.teamContent} direction='column'>
<Typography
variant='h2'
color='textPrimary'
gutterBottom
>
{team.name}
</Typography>
<Typography
variant='h4'
color='textSecondary'
gutterBottom
>
Motto: {team.profile.motto}
</Typography>
<Typography variant='h6' color='textPrimary' gutterBottom>
Description: {team.profile.description}
</Typography>
</Grid>
<Grid container className={classes.fbContent} direction='column'>
<Typography
variant='h4'
color='textSecondary'
gutterBottom
>
Financial Beings
</Typography>
<ManageTeamProfileFBView team={team} />
</Grid>
</Grid>
</Grid>
</React.Fragment>
)
}
ManageTeamProfileView.propTypes = {
classes: PropTypes.object.isRequired,
team: PropTypes.object.isRequired
}
export default withStyles(styles)(ManageTeamProfileView)
@@ -0,0 +1,121 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Paper from '@material-ui/core/Paper'
import Grid from '@material-ui/core/Grid'
import Button from '@material-ui/core/Button'
import { withStyles } from '@material-ui/core/styles'
import { Link } from 'react-router-dom'
import CreateTeamForm from './CreateTeamForm'
const styles = theme => ({
root: {
flexGrow: 1
},
'@global': {
body: {
backgroundColor: theme.palette.common.white
}
},
layout: {
width: 'auto',
marginLeft: theme.spacing.unit * 3,
marginRight: theme.spacing.unit * 3,
marginBottom: theme.spacing.unit * 6,
[theme.breakpoints.up(800 + theme.spacing.unit * 3 * 2)]: {
width: 800,
marginLeft: 'auto',
marginRight: 'auto'
}
},
paper: {
marginTop: 0,
marginBottom: theme.spacing.unit * 3,
padding: 0,
[theme.breakpoints.up(800 + theme.spacing.unit * 3 * 2)]: {
marginTop: theme.spacing.unit * 3,
marginBottom: theme.spacing.unit * 6,
padding: `0 0 ${theme.spacing.unit * 6}px`
}
},
heroContent: {
maxWidth: 800,
margin: '0 auto',
padding: 0
},
teamContent: {
margin: `${theme.spacing.unit * 1}px ${theme.spacing.unit * 3}px 0 0`
},
banner: {
maxWidth: '100%',
height: 'auto'
},
avatar: {
maxWidth: 100,
height: 100,
margin: `${theme.spacing.unit * 1}px 0 0 ${theme.spacing.unit * 3}px `
},
backLink: {
display: 'block',
textDecoration: 'none',
margin: `${theme.spacing.unit * 3}px 0 0`,
color: theme.palette.secondary.main
}
})
export class ManageTeamProfile extends Component {
constructor (props) {
super(props)
this.toggleEdit = this.toggleEdit.bind(this)
this.handleSave = this.handleSave.bind(this)
this.state = {
edit: false,
save: false
}
}
render () {
const { classes, team, slug, match } = this.props
return (
<div className='container'>
<Paper>
<Grid container spacing={0} direction='column' justify='stretch' alignItems='center'>
<Grid item xs={10}>
<Typography variant='h5' align='center'>
You don&rsquo;t have any teams. Create one!
</Typography>
<Typography variant='body1' align='center' gutterBottom>
To begin developing on the Advanced Algos platform, as well as participate in Algobot competitions,
you'll need to create a team. A default trading algobot will be cloned and added to your team so
that you can begin experimenting right away.
</Typography>
<CreateTeamForm />
</Grid>
</Grid>
</Paper>
</div>
)
}
toggleEdit () {
this.setState({ edit: !this.state.edit })
}
handleSave () {
this.setState({ save: !this.state.edit })
}
}
ManageTeamProfile.propTypes = {
classes: PropTypes.object.isRequired,
team: PropTypes.object.isRequired,
match: PropTypes.object.isRequired,
slug: PropTypes.string.isRequired
}
export default withStyles(styles)(ManageTeamProfile)
@@ -7,14 +7,16 @@ 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 Button from '@material-ui/core/Button'
import EditIcon from '@material-ui/icons/Edit'
import { Link } from 'react-router-dom'
import ManageTeamDetails from './ManageTeamDetails'
import ManageTeamDelete from './ManageTeamDelete'
import ManageTeamEdit from './ManageTeamEdit'
import log from '../../../utils/log'
export const ManageTeamsItem = ({ classes, team, ...props }) => {
export const ManageTeamsItem = ({ classes, team, match, ...props }) => {
log.debug('ManageTeamsItem', team, team.profile, team.profile.avatar)
let avatar
if (team.profile.avatar !== undefined && team.profile.avatar !== 'a') {
@@ -36,13 +38,22 @@ export const ManageTeamsItem = ({ classes, team, ...props }) => {
{team.name}
</Typography>
<Typography variant='caption' color='textSecondary'>
{team.createdAt} | Members: {team.members.length}
Members: {team.members.length} | Financial Beings: {1}
</Typography>
</CardContent>
<CardActions>
<ManageTeamDetails team={team} />
<ManageTeamEdit slug={team.slug} team={team} {...props} />
<ManageTeamDelete slug={team.slug} botSlug={team.fb[0].slug} />
<Grid container direction='row' justify='flex-end'>
<Button
size='small'
color='primary'
className={classes.buttonRight}
component={Link}
to={`${match.url}/${team.slug}`}
>
<EditIcon /> Manage Profile
</Button>
<ManageTeamDelete slug={team.slug} botSlug={team.fb[0].slug} />
</Grid>
</CardActions>
</div>
</Card>
@@ -52,7 +63,8 @@ export const ManageTeamsItem = ({ classes, team, ...props }) => {
ManageTeamsItem.propTypes = {
classes: PropTypes.object.isRequired,
team: PropTypes.object.isRequired
team: PropTypes.object.isRequired,
match: PropTypes.object
}
export default ManageTeamsItem
@@ -8,22 +8,24 @@ import Typography from '@material-ui/core/Typography'
import { MessageCard } from '@advancedalgos/web-components'
import { withStyles } from '@material-ui/core/styles'
import { isEmpty } from '../../../utils/js-helpers'
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
import ManageTeamsItem from './ManageTeamsItem'
import ManageTeamProfile from './ManageTeamProfile'
import CreateTeamForm from './CreateTeamForm'
import log from '../../../utils/log'
const styles = theme => ({
container: {
padding: `${theme.spacing.unit * 8}px ${theme.spacing.unit * 6}px`,
margin: `${theme.spacing.unit * 1}px 0`
root: {
flexGrow: 1
},
heroContent: {
maxWidth: 600,
margin: '0 auto',
padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px`
maxWidth: 800,
margin: `${theme.spacing.unit * 4}px auto`,
padding: 0
},
cardGrid: {
padding: `${theme.spacing.unit * 8}px 0`
@@ -51,13 +53,15 @@ const styles = theme => ({
}
})
export const ManageTeamsList = ({ classes, user = null, ...props }) => (
export const ManageTeamsList = ({ classes, match, ...props }) => (
<Query
query={GET_TEAMS_BY_OWNER}
fetchPolicy='network-only'
>
{({ loading, error, data }) => {
log.debug('GET_TEAMS_BY_OWNER: ', loading, error, data)
let slug = null
if (!isEmpty(match.params) && match.params.slug) slug = match.params.slug
let errors = null
if (error) {
@@ -68,54 +72,77 @@ export const ManageTeamsList = ({ classes, user = null, ...props }) => (
if (!loading && !error) {
if (data.teams_TeamsByOwner.length > 0) {
return (
<Grid container spacing={0} direction='column' justify='center' alignItems='center'>
{!loading &&
data.teams_TeamsByOwner.map(team => (
<ManageTeamsItem
key={team.id}
team={team}
classes={classes}
{...props}
/>
))}
{errors}
</Grid>
<div className={classes.root}>
<div className={slug === null ? classes.heroContent : ''}>
<Grid container spacing={8} direction='column' alignItems='stretch'>
{!loading &&
data.teams_TeamsByOwner.map(team => {
if (slug === team.slug) {
return (
<ManageTeamProfile
key={`team-profile-${team.id}`}
team={team}
slug={team.slug}
match={match}
{...props}
/>
)
} else {
return (
<ManageTeamsItem
key={`team-list-${team.id}`}
team={team}
classes={classes}
match={match}
{...props}
/>
)
}
})}
{errors}
</Grid>
</div>
</div>
)
} else {
return (
<Paper>
<Grid container spacing={0} direction='column' justify='center' alignItems='center' className={classes.container}>
<Grid item xs={10}>
<Typography variant='h5' align='center'>
You don&rsquo;t have any teams. Create one!
</Typography>
<Typography variant='body2' align='center' gutterBottom>
To begin developing on the Advanced Algos platform, as well as participate in Algobot competitions,
you'll need to create a team. A default trading algobot will be cloned and added to your team so
that you can begin experimenting right away.
</Typography>
<CreateTeamForm />
<div className={classes.root} >
<Paper>
<Grid container spacing={0} direction='column' justify='stretch' alignItems='center'>
<Grid item xs={10}>
<Typography variant='h5' align='center'>
You don&rsquo;t have any teams. Create one!
</Typography>
<Typography variant='body1' align='center' gutterBottom>
To begin developing on the Advanced Algos platform, as well as participate in Algobot competitions,
you'll need to create a team. A default trading algobot will be cloned and added to your team so
that you can begin experimenting right away.
</Typography>
<CreateTeamForm />
</Grid>
</Grid>
</Grid>
</Paper>
</Paper>
</div>
)
}
} else {
return (
<Grid spacing={0} direction='column' justify='center' alignItems='center'>
<Grid item xs={12}>
{errors === null &&
<Typography variant='h5' align='center' gutterBottom>
Loading...
</Typography>
}
{errors !== null &&
<Typography variant='h5' align='center' gutterBottom>
{errors}
</Typography>
}
<div className={classes.root} >
<Grid container spacing={0} direction='column' justify='center' alignItems='center'>
<Grid item xs={12}>
{errors === null &&
<Typography variant='h5' align='center' gutterBottom>
Loading...
</Typography>
}
{errors !== null &&
<Typography variant='h5' align='center' gutterBottom>
{errors}
</Typography>
}
</Grid>
</Grid>
</Grid>
</div>
)
}
}}
@@ -124,7 +151,8 @@ export const ManageTeamsList = ({ classes, user = null, ...props }) => (
ManageTeamsList.propTypes = {
user: PropTypes.any,
classes: PropTypes.object.isRequired
classes: PropTypes.object.isRequired,
match: PropTypes.object
}
export default withStyles(styles)(ManageTeamsList)
+12 -34
View File
@@ -1,47 +1,25 @@
import React from 'react'
import PropTypes from 'prop-types'
import { withStyles } from '@material-ui/core/styles'
import Grid from '@material-ui/core/Grid'
import { BannerTopBar } from '../common'
import ManageTeamsList from './components/ManageTeamsList'
const styles = theme => ({
container: {
width: 'auto',
marginTop: theme.spacing.unit * 3,
marginLeft: theme.spacing.unit * 3,
marginRight: theme.spacing.unit * 3,
marginBottom: theme.spacing.unit * 6,
[theme.breakpoints.up(800 + theme.spacing.unit * 3 * 2)]: {
width: 800,
marginLeft: 'auto',
marginRight: 'auto'
}
}
})
const ManageTeams = ({ classes, ...props }) => (
const ManageTeams = ({ match, ...props }) => (
<div>
<BannerTopBar size='medium' title='Manage Your Teams' text='Create and manage your Advanced Algos teams' backgroundUrl='https://advancedalgos.net/img/photos/teams.jpg' />
<Grid
container
direction='column'
justify='center'
alignItems='stretch'
className={classes.container}
spacing={0}
>
<Grid item spacing={0}>
<ManageTeamsList {...props} />
</Grid>
</Grid>
<BannerTopBar
size={match.params.slug !== undefined ? 'small' : 'medium'}
title='Manage Your Teams'
text='Discover, Create and manage Advanced Algos Teams'
backgroundUrl='https://advancedalgos.net/img/photos/teams.jpg'
/>
<div className='container'>
<ManageTeamsList {...props} match={match} />
</div>
</div>
)
ManageTeams.propTypes = {
classes: PropTypes.object.isRequired
match: PropTypes.object
}
export default withStyles(styles)(ManageTeams)
export default ManageTeams
@@ -0,0 +1,207 @@
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 SEND_MEMBER_INVITE from '../../../graphql/teams/SendMemberInvite'
// import { checkGraphQLError } from '../../../utils/graphql-errors'
const styles = theme => ({
dialogStyle: {
padding: '3em'
},
buttonRight: {
// position: 'absolute',
// right: '3em'
marginTop: '1em',
marginRight: 'auto',
marginLeft: 'auto',
display: 'block',
lineHeight: '1em'
}
})
export class InviteMemberDialog 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.state = {
open: false,
email: '',
errors: {
email: ''
}
}
}
render () {
const { classes, teamId } = this.props
if (this.state.open) {
return (
<Mutation mutation={SEND_MEMBER_INVITE} >
{(sendMemberInvite, { loading, error, data }) => {
console.log('sendMemberInvite: ', data)
let errors
let loader = null
if (loading) {
loader = (
<Typography variant='subtitle1'>Submitting invitation...</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'
>
<DialogTitle id='form-dialog-title'>Invite a New Team Member</DialogTitle>
<DialogContent>
{(data === undefined || data.sendMemberInviteSG !== 'Success') && (
<FormControl
required
error={this.state.errors.email !== '' || (error !== undefined || error !== null)}
>
<TextField
autoFocus
margin='dense'
id='email'
label='Email Address'
type='text'
fullWidth
value={this.state.email}
onChange={e => this.handleChange(e)}
error={this.state.errors.email !== ''}
/>
{this.state.errors.email !== '' && (
<FormHelperText>{this.state.errors.email}</FormHelperText>
)}
{error && <FormHelperText>{errors}</FormHelperText>}
{loader}
</FormControl>
)}
{data !== undefined && data.sendMemberInviteSG === 'Success' && (
<Typography variant='subtitle1'>Invitation successfully sent!</Typography>
)}
</DialogContent>
<DialogActions>
{(data === undefined || data.sendMemberInviteSG !== 'Success') && (
<React.Fragment>
<Button onClick={this.handleClose} color='primary'>
Cancel
</Button>
<Button
onClick={e => {
this.handleSubmit(e, sendMemberInvite, this.state.email, teamId)
}}
color='primary'
>
Send Invitation
</Button>
</React.Fragment>
)}
{data !== undefined && data.sendMemberInviteSG === 'Success' && (
<Button onClick={this.handleClose} color='primary'>
Close
</Button>
)}
</DialogActions>
</Dialog>
</div>
)
}}
</Mutation>
)
} else {
return (
<Button
variant='fab'
color='primary'
aria-label='Add'
className={classes.buttonRight}
onClick={this.handleClickOpen}
>
<AddIcon />
</Button>
)
}
}
handleClickOpen () {
this.setState({ open: true })
}
handleClose () {
this.setState({ open: false })
}
handleChange (e) {
const errors = this.validate(e.target.value)
if (isEmpty(errors)) {
this.setState({ errors: { email: '' } })
this.setState({ email: e.target.value })
} else {
this.setState({ errors: errors })
this.setState({ email: e.target.value })
}
}
async handleSubmit (e, sendMemberInvite, email, teamId) {
e.preventDefault()
console.log('sendMemberInvite submit: ', email, teamId)
await sendMemberInvite({ variables: { email, teamId } })
this.setState({ email: '' })
}
validate (data) {
const errors = {}
if (data === '') errors.email = 'Please enter an email address'
return errors
}
}
InviteMemberDialog.propTypes = {
classes: PropTypes.object.isRequired,
teamId: PropTypes.string
}
export default withStyles(styles)(InviteMemberDialog)
@@ -32,7 +32,7 @@ export const ManageMembersItem = ({ classes, member, teamId, authId }) => {
</Typography>
</Grid>
<Grid item xs={4}>
<Typography color='textSecondary' variant='body2' component='h4' align='left' >
<Typography color='textSecondary' variant='body1' component='h4' align='left' >
{email !== null ? `${memberStatus[memberStatus.length - 1].status} | Sent: ${memberStatus[memberStatus.length - 1].createdAt}` : `${member.role} | Member since: `}
</Typography>
</Grid>
@@ -63,7 +63,7 @@ export const ManageMembersTeamItem = ({ classes, team, authId }) => {
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'
avatar = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-avatar-default.png'
}
if (team.members.length > 0) {
return (
@@ -1,7 +1,6 @@
import React from 'react'
import PropTypes from 'prop-types'
import CssBaseline from '@material-ui/core/CssBaseline'
import Typography from '@material-ui/core/Typography'
import Paper from '@material-ui/core/Paper'
import Grid from '@material-ui/core/Grid'
@@ -9,6 +8,8 @@ import { withStyles } from '@material-ui/core/styles'
import { Link } from 'react-router-dom'
import TeamsFBView from './TeamsFBView'
const styles = theme => ({
root: {
flexGrow: 1
@@ -19,9 +20,7 @@ const styles = theme => ({
}
},
layout: {
width: 'auto',
marginLeft: theme.spacing.unit * 3,
marginRight: theme.spacing.unit * 3,
width: '100%',
marginBottom: theme.spacing.unit * 6,
[theme.breakpoints.up(800 + theme.spacing.unit * 3 * 2)]: {
width: 800,
@@ -34,27 +33,60 @@ const styles = theme => ({
marginBottom: theme.spacing.unit * 3,
padding: 0,
[theme.breakpoints.up(800 + theme.spacing.unit * 3 * 2)]: {
marginTop: theme.spacing.unit * 6,
marginTop: theme.spacing.unit * 3,
marginBottom: theme.spacing.unit * 6,
padding: `0 0 ${theme.spacing.unit * 6}px`
padding: `0 0 ${theme.spacing.unit * 2}px`
}
},
heroContent: {
maxWidth: 800,
margin: '0 auto',
padding: `0 0 ${theme.spacing.unit * 6}px`
padding: `0 0 ${theme.spacing.unit * 2}px`
},
metaContainer: {
marginTop: `${theme.spacing.unit * 1}px`,
alignSelf: 'stretch',
borderRight: '1px solid #CCCCCC'
},
teamMeta: {
margin: `${theme.spacing.unit * 3}px 0 0`,
paddingLeft: `${theme.spacing.unit * 2}px`,
textAlign: 'center'
},
teamContent: {
margin: `${theme.spacing.unit * 1}px ${theme.spacing.unit * 3}px 0 0`
'& h2': {
padding: `${theme.spacing.unit * 4}px ${theme.spacing.unit * 3}px ${theme.spacing.unit * 2}px`
},
'& h4': {
padding: `0 ${theme.spacing.unit * 3}px ${theme.spacing.unit * 2}px`
},
'& h6': {
padding: `0 ${theme.spacing.unit * 3}px 0`
}
},
fbContent: {
borderTop: '1px solid #CCCCCC',
width: '90%',
margin: `${theme.spacing.unit * 3}px auto`,
paddingTop: `${theme.spacing.unit * 3}px`
},
banner: {
maxWidth: '100%',
height: 'auto'
height: 'auto',
width: '100%'
},
avatar: {
maxWidth: 100,
height: 100,
margin: `${theme.spacing.unit * 1}px 0 0 ${theme.spacing.unit * 3}px `
maxWidth: 125,
height: 125,
margin: `0 auto ${theme.spacing.unit * 2}px`,
verticalAlign: 'middle',
borderRadius: '50%'
},
backLink: {
display: 'block',
textDecoration: 'none',
margin: `${theme.spacing.unit * 3}px 0 0`,
color: theme.palette.secondary.main
}
})
@@ -63,25 +95,38 @@ const TeamsDetails = ({ classes, team }) => {
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'
avatar = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-avatar-default.png'
}
let banner
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'
banner = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-banner-default.png'
}
const created = new Date(team.createdAt)
return (
<React.Fragment>
<CssBaseline />
<div className='container'>
<main className={classes.layout}>
<Link to='/teams'>&larr; Back to all teams</Link>
<Link to='/teams/explore' className={classes.backLink}>&larr; Back to all teams</Link>
<Paper className={classes.paper}>
<div className={classes.heroContent}>
<img src={banner} alt={team.name} className={classes.banner} />
<Grid container>
<Grid md={3}>
<img src={avatar} alt={team.name} className={classes.avatar} />
<Grid md={3} className={classes.metaContainer}>
<Grid container className={classes.teamMeta} direction='column' justify='center'>
<img src={avatar} alt={team.name} className={classes.avatar} />
<Typography variant='subtitle1' paragraph gutterBottom>
Members: {team.members.length}
</Typography>
<Typography variant='subtitle1' paragraph gutterBottom>
Financial Beings: 1
</Typography>
<Typography variant='subtitle1' paragraph gutterBottom>
Created: {created.toLocaleDateString()}
</Typography>
</Grid>
</Grid>
<Grid md={9}>
<Grid container className={classes.teamContent} direction='column'>
@@ -92,25 +137,33 @@ const TeamsDetails = ({ classes, team }) => {
>
{team.name}
</Typography>
<Typography variant='subtitle1' color='textSecondary'>
{team.createdAt}
</Typography>
<Typography variant='subtitle1' color='textSecondary'>
<Typography
variant='h4'
color='textSecondary'
gutterBottom
>
Motto: {team.profile.motto}
</Typography>
<Typography variant='subtitle1' color='textSecondary'>
<Typography variant='h6' color='textPrimary' gutterBottom>
Description: {team.profile.description}
</Typography>
<Typography variant='subtitle1' paragraph gutterBottom>
Members: {team.members.length}
</Grid>
<Grid container className={classes.fbContent} direction='column'>
<Typography
variant='h4'
color='textSecondary'
gutterBottom
>
Financial Beings
</Typography>
<TeamsFBView team={team} />
</Grid>
</Grid>
</Grid>
</div>
</Paper>
</main>
</React.Fragment>
</div>
)
}
TeamsDetails.propTypes = {
@@ -0,0 +1,70 @@
import React from 'react'
import PropTypes from 'prop-types'
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 { withStyles } from '@material-ui/core/styles'
import log from '../../../utils/log'
const styles = theme => ({
fbContainer: {
margin: `0 0 ${theme.spacing.unit * 2}px`
},
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 TeamsFBView = ({ classes, team }) => {
log.debug('ManageTeamProvileFBView', team, team.fb[0], team.fb[0].avatar)
let avatar = (team.fb[0].avatar !== undefined && team.fb[0].avatar !== null) ? team.fb[0].avatar : 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-avatar-default.png'
return (
<Grid item xs={12} className={classes.fbContainer}>
<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>
</div>
</Card>
</Grid>
)
}
TeamsFBView.propTypes = {
classes: PropTypes.object.isRequired,
team: PropTypes.object.isRequired
}
export default withStyles(styles)(TeamsFBView)
+53 -22
View File
@@ -4,14 +4,40 @@ import PropTypes from 'prop-types'
import Grid from '@material-ui/core/Grid'
import Card from '@material-ui/core/Card'
import CardActionArea from '@material-ui/core/CardActionArea'
import CardActions from '@material-ui/core/CardActions'
import CardContent from '@material-ui/core/CardContent'
import CardMedia from '@material-ui/core/CardMedia'
import Button from '@material-ui/core/Button'
import Typography from '@material-ui/core/Typography'
import { withStyles } from '@material-ui/core/styles'
import { Link } from 'react-router-dom'
// const TeamDetailsLink = ({ teamSlug, ...props }) => <Link to={`/teams/${teamSlug}`} {...props} />
const styles = theme => ({
card: {
height: '100%',
display: 'flex',
flexDirection: 'column'
},
cardMedia: {
paddingTop: '25%', // 16:9
width: '100%'
},
cardContent: {
flexGrow: 1
},
avatar: {
maxWidth: 65,
height: 65,
margin: '0 0.875em 0 0',
borderRadius: '50%',
verticalAlign: 'middle',
alignSelf: 'flex-start'
},
buttonRight: {
textDecoration: 'none'
}
})
export const TeamsItem = ({ classes, team }) => {
let avatar
if (team.profile.avatar !== undefined && team.profile.avatar !== 'a') {
@@ -26,9 +52,9 @@ export const TeamsItem = ({ classes, team }) => {
banner = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-banner-default.png'
}
return (
<Grid item sm={6} md={4}>
<Grid item xs={12} sm={6} md={4}>
<Card className={classes.card}>
<CardActionArea>
<CardActionArea component={Link} to={`/teams/${team.slug}`}>
<CardMedia
className={classes.cardMedia}
image={banner}
@@ -36,30 +62,35 @@ export const TeamsItem = ({ classes, team }) => {
/>
<CardContent className={classes.cardContent}>
<Grid container>
<Grid item md={3}>
<Grid item md={3} >
<img src={avatar} alt={team.name} className={classes.avatar} />
</Grid>
<Grid item md={9}>
<Typography gutterBottom variant='h5' component='h2'>
{team.name}
</Typography>
<Typography variant='caption' paragraph gutterBottom>
Members: 1
</Typography>
<Typography variant='subtitle1' color='primary'>
Now recruiting!
</Typography>
<Grid container direction='column'>
<Grid item xs={12}>
<Typography gutterBottom variant='h5' component='h2'>
{team.name}
</Typography>
</Grid>
<Grid item xs={12}>
<Grid container spacing={8}>
<Grid item xs={6}>
<Typography variant='caption'>
Members: 1
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant='caption'>
Financial Beings: 1
</Typography>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
</CardContent>
</CardActionArea>
<CardActions>
<Link to={`/teams/${team.slug}`}>
<Button size='small' color='primary' className={classes.buttonRight}>
Details
</Button>
</Link>
</CardActions>
</Card>
</Grid>
)
@@ -70,4 +101,4 @@ TeamsItem.propTypes = {
team: PropTypes.object.isRequired
}
export default TeamsItem
export default withStyles(styles)(TeamsItem)
+8 -33
View File
@@ -16,32 +16,8 @@ import TeamsItem from './TeamsItem'
import TeamsDetails from './TeamsDetails'
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`
},
card: {
height: '100%',
display: 'flex',
flexDirection: 'column'
},
cardMedia: {
paddingTop: '25%' // 16:9
},
cardContent: {
flexGrow: 1
},
avatar: {
maxWidth: 50,
height: 50,
margin: '0 1em 1em 0'
},
buttonRight: {
justifyContent: 'flex-end'
teamListsContainer: {
margin: `${theme.spacing.unit * 3}px 0 ${theme.spacing.unit * 6}px`
}
})
@@ -67,7 +43,7 @@ export const TeamsList = ({ classes, match }) => (
if (data.teams_Teams.edges.length > 0) {
if (slug !== null) {
return (
<Grid container spacing={40}>
<Grid container >
{!loading &&
data.teams_Teams.edges.map(team => {
if (team.node.slug === slug) {
@@ -82,32 +58,31 @@ export const TeamsList = ({ classes, match }) => (
)
} else {
return (
<React.Fragment>
<Grid container spacing={40}>
<div className={classes.teamListsContainer} >
<Grid container spacing={24}>
{!loading &&
data.teams_Teams.edges.map(team => (
<TeamsItem
key={team.node.id}
team={team.node}
classes={classes}
/>
))}
{queryLoader}
{errors}
</Grid>
</React.Fragment>
</div>
)
}
} else {
return (
<Grid container spacing={40}>
<Grid container>
<MessageCard message='No teams found' />
</Grid>
)
}
} else {
return (
<Grid container spacing={40}>
<Grid container>
<MessageCard message='Loading...' />
{queryLoader}
{errors}
+3 -3
View File
@@ -31,10 +31,10 @@ const styles = theme => ({
const Teams = ({ classes, match }) => (
<React.Fragment>
<BannerTopBar size='medium' title='Browse Teams' text='Explore Advanced Algos Teams' backgroundUrl='https://advancedalgos.net/img/photos/teams.jpg' />
<main className={classes.layout}>
<BannerTopBar size={match.params.slug !== undefined ? 'small' : 'medium'} title='Browse Teams' text='Explore Advanced Algos Teams' backgroundUrl='https://advancedalgos.net/img/photos/teams.jpg' />
<div className='container'>
<TeamsList match={match} />
</main>
</div>
</React.Fragment>
)
+1 -1
View File
@@ -8,7 +8,7 @@ export const theme = createMuiTheme({
secondary: indigo
},
typography: {
fontFamily: '"Saira","Saira Condenses", sans-serif'
fontFamily: '"Saira","Saira Condensed", sans-serif'
},
overrides: {
Paper: {