From 43f2bbceeeeff7db7dc31aed7e8fd1a6f33ff9ce Mon Sep 17 00:00:00 2001 From: Barry Low Date: Wed, 12 Sep 2018 21:41:38 -0700 Subject: [PATCH 01/16] Server: Update resolver to use auth context --- api/.graphqlconfig.yml | 2 +- api/Dockerfile | 2 +- api/database/datamodel.graphql | 3 +- api/docker-compose.api.yml | 19 + api/docker-compose.yml | 19 - api/package-lock.json | 120 +- api/package.json | 2 +- api/src/auth/authDirectives.js | 44 +- api/src/auth/validateIdToken.js | 4 +- api/src/generated/prisma.graphql | 2327 +++++++++++++++++++ api/src/index.js | 84 +- api/src/{schema.graphqls => schema.graphql} | 35 +- client/src/views/index.js | 3 +- client/src/views/teams/index.js | 53 + docs/CodeStyle.md | 5 + 15 files changed, 2577 insertions(+), 145 deletions(-) create mode 100644 api/docker-compose.api.yml create mode 100644 api/src/generated/prisma.graphql rename api/src/{schema.graphqls => schema.graphql} (69%) create mode 100644 client/src/views/teams/index.js create mode 100644 docs/CodeStyle.md diff --git a/api/.graphqlconfig.yml b/api/.graphqlconfig.yml index a35fd2e44..d65be026a 100644 --- a/api/.graphqlconfig.yml +++ b/api/.graphqlconfig.yml @@ -4,7 +4,7 @@ projects: extensions: endpoints: dev1: - url: http://0.0.0.0:4000/graphql + url: http://localhost:4001/graphql database: schemaPath: src/generated/prisma.graphql diff --git a/api/Dockerfile b/api/Dockerfile index 0506ccdef..32704198c 100644 --- a/api/Dockerfile +++ b/api/Dockerfile @@ -1,6 +1,6 @@ FROM mhart/alpine-node:8 -ENV PORT=4000 +ENV PORT=4001 RUN mkdir -p /var/www/app && \ mkdir -p /var/www/app/node_modules diff --git a/api/database/datamodel.graphql b/api/database/datamodel.graphql index 0ba5945e1..7a55f466d 100644 --- a/api/database/datamodel.graphql +++ b/api/database/datamodel.graphql @@ -30,6 +30,7 @@ type Team { slug: String! @unique profile: TeamProfile members: [TeamMembers!]! @relation (name: "TeamMembers", onDelete: SET_NULL) + owner: String! wallet: Wallet fb: [FinancialBeings!]! @relation (name: "TeamFinancialBeing", onDelete: SET_NULL) status: [TeamStatus!]! @@ -59,7 +60,7 @@ type TeamMembers { type Member { id: ID! @unique - nickname: String + alias: String team: TeamMembers @relation (name: "MemberOnTeam", onDelete: SET_NULL) authId: String! @unique visible: Boolean! @default(value: true) diff --git a/api/docker-compose.api.yml b/api/docker-compose.api.yml new file mode 100644 index 000000000..689c37fa6 --- /dev/null +++ b/api/docker-compose.api.yml @@ -0,0 +1,19 @@ +version: '3' +services: + api: + image: aateamapi-dev:v1 + build: + context: . + dockerfile: ./Dockerfile + env_file: ./.env + container_name: aateamapi + tty: true + stdin_open: true + volumes: + - ./:/var/www/app + - /var/www/app/node_modules + working_dir: /var/www/app + restart: always + command: node -r dotenv/config src/index.js + ports: + - "4001:4001" diff --git a/api/docker-compose.yml b/api/docker-compose.yml index 37a6ee436..57dc62ef6 100644 --- a/api/docker-compose.yml +++ b/api/docker-compose.yml @@ -27,24 +27,5 @@ services: POSTGRES_PASSWORD: prisma volumes: - postgres:/var/lib/postgresql/data - node: - image: aateamapi-dev:v1 - build: - context: . - dockerfile: ./Dockerfile - depends_on: - - prisma - env_file: ./.env - container_name: aateamapi - tty: true - stdin_open: true - volumes: - - ./:/var/www/app - - /var/www/app/node_modules - working_dir: /var/www/app - restart: always - command: node -r dotenv/config src/index.js - ports: - - "4000:4000" volumes: postgres: diff --git a/api/package-lock.json b/api/package-lock.json index f49d52a1e..d43af47d4 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -568,7 +568,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -614,7 +614,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -923,7 +923,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -1462,7 +1462,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -1492,9 +1492,9 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "config-chain": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.11.tgz", - "integrity": "sha1-q6CXR9++TD5w52am5BWG4YWfxvI=", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", + "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", "dev": true, "requires": { "ini": "^1.3.4", @@ -1640,7 +1640,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -4997,7 +4997,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -5366,7 +5366,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -6371,14 +6371,14 @@ "dev": true }, "prisma": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-1.15.3.tgz", - "integrity": "sha512-95s0Kk8PtptrVhp4ajXPd7A7QrbWdCEyZ/nnvcz0Sz9nzufYYZfBjxgibUyoaNs/XL0KXtiibQIdZhpWIJgOhw==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-1.16.0.tgz", + "integrity": "sha512-8jZYCrkd1xjy+JJbQi81f8PBOLe8LLWwSu0fK0cqekm3FeafBd8xk5b0RWcIsHyVd6ypKCQt3tnZEMVzmbKrdQ==", "dev": true, "requires": { "fs-extra": "^5.0.0", - "prisma-cli-core": "1.0.75", - "prisma-cli-engine": "1.0.78", + "prisma-cli-core": "1.0.76", + "prisma-cli-engine": "1.0.79", "semver": "^5.4.1", "source-map-support": "^0.4.18" }, @@ -6497,9 +6497,9 @@ } }, "prisma-cli-core": { - "version": "1.0.75", - "resolved": "https://registry.npmjs.org/prisma-cli-core/-/prisma-cli-core-1.0.75.tgz", - "integrity": "sha512-DiH686w2u9aiz4RoNX3T0XgGzeai8IrXX/Qsocam+lKtBB63aupqCxbj6kp16sNoiXhDPzI2Zx/Hwm0GG9sUhw==", + "version": "1.0.76", + "resolved": "https://registry.npmjs.org/prisma-cli-core/-/prisma-cli-core-1.0.76.tgz", + "integrity": "sha512-HtHn/RM2GlJi23KoIXHoboP97aC54SYDqr7B4uT/80JP6A6nQp5HLt4sJgNfKapaHFZVzXYM7M3LEfGq3tgQbw==", "dev": true, "requires": { "adm-zip": "^0.4.7", @@ -6533,9 +6533,9 @@ "opn": "^5.1.0", "pause": "^0.1.0", "portfinder": "^1.0.13", - "prisma-db-introspection": "0.0.45", + "prisma-db-introspection": "0.0.46", "prisma-json-schema": "0.0.4", - "prisma-yml": "1.0.90", + "prisma-yml": "1.0.96", "scuid": "^1.0.2", "semver": "^5.4.1", "sillyname": "^0.1.0", @@ -6599,12 +6599,12 @@ } }, "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "dotenv": { @@ -6693,7 +6693,7 @@ }, "graphql-import": { "version": "0.4.5", - "resolved": "https://registry.npmjs.org/graphql-import/-/graphql-import-0.4.5.tgz", + "resolved": "http://registry.npmjs.org/graphql-import/-/graphql-import-0.4.5.tgz", "integrity": "sha512-G/+I08Qp6/QGTb9qapknCm3yPHV0ZL7wbaalWFpxsfR8ZhZoTBe//LsbsCKlbALQpcMegchpJhpTSKiJjhaVqQ==", "dev": true, "requires": { @@ -6766,12 +6766,6 @@ "regex-cache": "^0.4.2" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, "prisma-json-schema": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/prisma-json-schema/-/prisma-json-schema-0.0.4.tgz", @@ -6779,9 +6773,9 @@ "dev": true }, "prisma-yml": { - "version": "1.0.90", - "resolved": "https://registry.npmjs.org/prisma-yml/-/prisma-yml-1.0.90.tgz", - "integrity": "sha512-i5qMN/p1YvLV931YgfJtUAaHO7nOL07oW/EqQ1AixBGRi9nB21TpZGy9b50TwunaMt8LfVYB5ER82338qrJA5g==", + "version": "1.0.96", + "resolved": "https://registry.npmjs.org/prisma-yml/-/prisma-yml-1.0.96.tgz", + "integrity": "sha512-w3XGzJHUq5pwBoFy/amkGOcTDj4XoHh8UFUUUZcHo5fSyoF8AWeRTu1yWINaPVGxbcmpwKNetntAW4ijiq7M5g==", "dev": true, "requires": { "ajv": "5", @@ -6828,9 +6822,9 @@ } }, "prisma-cli-engine": { - "version": "1.0.78", - "resolved": "https://registry.npmjs.org/prisma-cli-engine/-/prisma-cli-engine-1.0.78.tgz", - "integrity": "sha512-chtmecxBgXPQUzvDS0U/R+pHZ/nzV1ksO+OiKr98kT7dBR9QJQbRG0v/j+zoIW4vdR9eyIaXy5i+dW8HU8XnDg==", + "version": "1.0.79", + "resolved": "https://registry.npmjs.org/prisma-cli-engine/-/prisma-cli-engine-1.0.79.tgz", + "integrity": "sha512-CdEIJs4ld1IiQQt2CFFPmeDypN4Ct4sTgmFODVjJix790mpEtxMagzCcA+mhfnRL65P6xiHn76Gdxbz60GyYBA==", "dev": true, "requires": { "@heroku/linewrap": "^1.0.0", @@ -6873,7 +6867,7 @@ "memfs": "^2.5.3", "opn": "^5.1.0", "prisma-json-schema": "0.0.4", - "prisma-yml": "1.0.90", + "prisma-yml": "1.0.96", "raven": "2.3.0", "replaceall": "^0.1.6", "rwlockfile": "^1.4.8", @@ -6890,12 +6884,12 @@ }, "dependencies": { "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "dotenv": { @@ -6931,12 +6925,6 @@ "through": "^2.3.6" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, "prisma-json-schema": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/prisma-json-schema/-/prisma-json-schema-0.0.4.tgz", @@ -6944,9 +6932,9 @@ "dev": true }, "prisma-yml": { - "version": "1.0.90", - "resolved": "https://registry.npmjs.org/prisma-yml/-/prisma-yml-1.0.90.tgz", - "integrity": "sha512-i5qMN/p1YvLV931YgfJtUAaHO7nOL07oW/EqQ1AixBGRi9nB21TpZGy9b50TwunaMt8LfVYB5ER82338qrJA5g==", + "version": "1.0.96", + "resolved": "https://registry.npmjs.org/prisma-yml/-/prisma-yml-1.0.96.tgz", + "integrity": "sha512-w3XGzJHUq5pwBoFy/amkGOcTDj4XoHh8UFUUUZcHo5fSyoF8AWeRTu1yWINaPVGxbcmpwKNetntAW4ijiq7M5g==", "dev": true, "requires": { "ajv": "5", @@ -7002,9 +6990,9 @@ } }, "prisma-db-introspection": { - "version": "0.0.45", - "resolved": "https://registry.npmjs.org/prisma-db-introspection/-/prisma-db-introspection-0.0.45.tgz", - "integrity": "sha512-tOdv4mBFZLVds1Wst92l2iarmzlxwFo/EFHs4kW1P0rR2My7BoxRgV0HSZy9xvo9gbU3P8e5JEZofMNrS+5v+g==", + "version": "0.0.46", + "resolved": "https://registry.npmjs.org/prisma-db-introspection/-/prisma-db-introspection-0.0.46.tgz", + "integrity": "sha512-/b7evS9b5xKS7UrcOERkCmV+IWC6OAgFtInFsvdwn4MeLEaVbkOfzRakdOo+t2gb+N7Yy8Eey9eKYgB5jiJAbA==", "dev": true, "requires": { "ajv": "5", @@ -7029,12 +7017,12 @@ }, "dependencies": { "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "dotenv": { @@ -7043,12 +7031,6 @@ "integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0=", "dev": true }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, "prisma-json-schema": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/prisma-json-schema/-/prisma-json-schema-0.0.1.tgz", @@ -7608,7 +7590,7 @@ "dependencies": { "commander": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "resolved": "http://registry.npmjs.org/commander/-/commander-2.8.1.tgz", "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", "dev": true, "requires": { @@ -8196,7 +8178,7 @@ }, "table": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.3.tgz", + "resolved": "http://registry.npmjs.org/table/-/table-4.0.3.tgz", "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==", "dev": true, "requires": { @@ -8257,7 +8239,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -8522,7 +8504,7 @@ }, "buffer": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", + "resolved": "http://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", "integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=", "dev": true, "requires": { @@ -9105,7 +9087,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { diff --git a/api/package.json b/api/package.json index 9df8a2bf9..8bc857126 100644 --- a/api/package.json +++ b/api/package.json @@ -22,6 +22,6 @@ "devDependencies": { "graphql-cli": "^2.16.5", "npm-run-all": "4.1.3", - "prisma": "^1.14.0" + "prisma": "^1.16.0" } } diff --git a/api/src/auth/authDirectives.js b/api/src/auth/authDirectives.js index 56720ff10..f098fa4ec 100644 --- a/api/src/auth/authDirectives.js +++ b/api/src/auth/authDirectives.js @@ -1,6 +1,5 @@ const _get = require('lodash.get') -const validateAndParseIdToken = require('./helpers/validateAndParseIdToken') -const createMember = require('./index') +const { validateIdToken } = require('./validateIdToken') const memberLocationOnContext = 'request.member' const bearerAccessToken = 'request.headers.authorization' @@ -8,11 +7,29 @@ const bearerAccessToken = 'request.headers.authorization' const ctxMember = ctx => _get(ctx, memberLocationOnContext) const ctxToken = ctx => _get(ctx, bearerAccessToken) +const createMember = async (ctx, idToken, info) => { + console.log('createMember', idToken) + const member = await ctx.db.mutation.upsertMember({ + where: { + authId: idToken.sub, + }, + create: { + authId: idToken.sub, + alias: idToken.nickname + }, + update: { + authId: idToken.sub, + alias: idToken.nickname + } + }, info) + return member +} + const isLoggedIn = async ctx => { let member = ctxMember(ctx, memberLocationOnContext) let token = ctxToken(ctx, bearerAccessToken) let memberToken - + console.log('isLoggedIn: ', member, token) if (!member && token) { let scheme, credentials const tokenParts = token.split(' ') @@ -24,21 +41,28 @@ const isLoggedIn = async ctx => { if (/^Bearer$/i.test(scheme)) { token = credentials //verify token + console.log('isLoggedIn2 : ', token) try { - memberToken = await validateAndParseIdToken(token) - const auth0id = memberToken.sub + memberToken = await validateIdToken(token) + const authId = memberToken.sub + console.log('isLoggedIn3 : ', await authId, ctx.db.query.member) + exists = await ctx.db.query.member({ where: { authId: authId } }) + console.log('isLoggedIn4 : ', await exists, createMember ) + if (!member && exists === null) { + member = await createMember(ctx, memberToken).then(res => { + console.log('isLoggedIn5 : ', res) + return res + }) - member = await ctx.db.query.member({ where: { auth0id } }) - - if (!member) { - member = await createMember(ctx, memberToken) + return member } + return member } catch (err) { memberToken = false } } } - + console.log('isLoggedIn5 : ', await member) if (!member) { throw new Error(`Not logged in`) } diff --git a/api/src/auth/validateIdToken.js b/api/src/auth/validateIdToken.js index 25434c85f..dd0b794b3 100644 --- a/api/src/auth/validateIdToken.js +++ b/api/src/auth/validateIdToken.js @@ -7,7 +7,7 @@ const jwks = jwksClient({ jwksUri: `https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json` }) -const validateParseIdToken = idToken => +const validateIdToken = idToken => new Promise((resolve, reject) => { const { header, payload } = jwt.decode(idToken, { complete: true }) if (!header || !header.kid || !payload) reject(new Error('Invalid Token')) @@ -25,4 +25,4 @@ const validateParseIdToken = idToken => }) }) -module.exports = validateParseIdToken +module.exports = { validateIdToken } diff --git a/api/src/generated/prisma.graphql b/api/src/generated/prisma.graphql new file mode 100644 index 000000000..6d118e29a --- /dev/null +++ b/api/src/generated/prisma.graphql @@ -0,0 +1,2327 @@ +# source: http://localhost:4466 +# timestamp: Wed Sep 12 2018 08:41:57 GMT-0700 (Pacific Daylight Time) + +type AggregateFBStatus { + count: Int! +} + +type AggregateFinancialBeings { + count: Int! +} + +type AggregateMember { + count: Int! +} + +type AggregateMemberStatus { + count: Int! +} + +type AggregateTeam { + count: Int! +} + +type AggregateTeamMembers { + count: Int! +} + +type AggregateTeamProfile { + count: Int! +} + +type AggregateTeamStatus { + count: Int! +} + +type AggregateWallet { + count: Int! +} + +type BatchPayload { + """The number of nodes that have been affected by the Batch operation.""" + count: Long! +} + +scalar DateTime + +enum FBKind { + TRADER + INDICATOR + EXTRACTOR + PLOTTER +} + +type FBStatus { + status: Status + reason: String + createdAt: DateTime! +} + +"""A connection to a list of items.""" +type FBStatusConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [FBStatusEdge]! + aggregate: AggregateFBStatus! +} + +input FBStatusCreateInput { + status: Status + reason: String +} + +input FBStatusCreateManyInput { + create: [FBStatusCreateInput!] +} + +"""An edge in a connection.""" +type FBStatusEdge { + """The item at the end of the edge.""" + node: FBStatus! + + """A cursor for use in pagination.""" + cursor: String! +} + +enum FBStatusOrderByInput { + status_ASC + status_DESC + reason_ASC + reason_DESC + createdAt_ASC + createdAt_DESC + id_ASC + id_DESC + updatedAt_ASC + updatedAt_DESC +} + +type FBStatusPreviousValues { + status: Status + reason: String + createdAt: DateTime! +} + +type FBStatusSubscriptionPayload { + mutation: MutationType! + node: FBStatus + updatedFields: [String!] + previousValues: FBStatusPreviousValues +} + +input FBStatusSubscriptionWhereInput { + """Logical AND on all given filters.""" + AND: [FBStatusSubscriptionWhereInput!] + + """Logical OR on all given filters.""" + OR: [FBStatusSubscriptionWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [FBStatusSubscriptionWhereInput!] + + """ + The subscription event gets dispatched when it's listed in mutation_in + """ + mutation_in: [MutationType!] + + """ + The subscription event gets only dispatched when one of the updated fields names is included in this list + """ + updatedFields_contains: String + + """ + The subscription event gets only dispatched when all of the field names included in this list have been updated + """ + updatedFields_contains_every: [String!] + + """ + The subscription event gets only dispatched when some of the field names included in this list have been updated + """ + updatedFields_contains_some: [String!] + node: FBStatusWhereInput +} + +input FBStatusUpdateInput { + status: Status + reason: String +} + +input FBStatusUpdateManyInput { + create: [FBStatusCreateInput!] +} + +input FBStatusWhereInput { + """Logical AND on all given filters.""" + AND: [FBStatusWhereInput!] + + """Logical OR on all given filters.""" + OR: [FBStatusWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [FBStatusWhereInput!] + status: Status + + """All values that are not equal to given value.""" + status_not: Status + + """All values that are contained in given list.""" + status_in: [Status!] + + """All values that are not contained in given list.""" + status_not_in: [Status!] + reason: String + + """All values that are not equal to given value.""" + reason_not: String + + """All values that are contained in given list.""" + reason_in: [String!] + + """All values that are not contained in given list.""" + reason_not_in: [String!] + + """All values less than the given value.""" + reason_lt: String + + """All values less than or equal the given value.""" + reason_lte: String + + """All values greater than the given value.""" + reason_gt: String + + """All values greater than or equal the given value.""" + reason_gte: String + + """All values containing the given string.""" + reason_contains: String + + """All values not containing the given string.""" + reason_not_contains: String + + """All values starting with the given string.""" + reason_starts_with: String + + """All values not starting with the given string.""" + reason_not_starts_with: String + + """All values ending with the given string.""" + reason_ends_with: String + + """All values not ending with the given string.""" + reason_not_ends_with: String + createdAt: DateTime + + """All values that are not equal to given value.""" + createdAt_not: DateTime + + """All values that are contained in given list.""" + createdAt_in: [DateTime!] + + """All values that are not contained in given list.""" + createdAt_not_in: [DateTime!] + + """All values less than the given value.""" + createdAt_lt: DateTime + + """All values less than or equal the given value.""" + createdAt_lte: DateTime + + """All values greater than the given value.""" + createdAt_gt: DateTime + + """All values greater than or equal the given value.""" + createdAt_gte: DateTime +} + +enum FBType { + BOT + NET + ADVANCED +} + +type FinancialBeings implements Node { + id: ID! + type: FBType + kind: FBKind + team(where: TeamWhereInput): Team + status(where: FBStatusWhereInput, orderBy: FBStatusOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [FBStatus!] + updatedAt: DateTime! + createdAt: DateTime! +} + +"""A connection to a list of items.""" +type FinancialBeingsConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [FinancialBeingsEdge]! + aggregate: AggregateFinancialBeings! +} + +input FinancialBeingsCreateInput { + type: FBType + kind: FBKind + team: TeamCreateOneWithoutFbInput + status: FBStatusCreateManyInput +} + +input FinancialBeingsCreateManyWithoutTeamInput { + create: [FinancialBeingsCreateWithoutTeamInput!] + connect: [FinancialBeingsWhereUniqueInput!] +} + +input FinancialBeingsCreateWithoutTeamInput { + type: FBType + kind: FBKind + status: FBStatusCreateManyInput +} + +"""An edge in a connection.""" +type FinancialBeingsEdge { + """The item at the end of the edge.""" + node: FinancialBeings! + + """A cursor for use in pagination.""" + cursor: String! +} + +enum FinancialBeingsOrderByInput { + id_ASC + id_DESC + type_ASC + type_DESC + kind_ASC + kind_DESC + updatedAt_ASC + updatedAt_DESC + createdAt_ASC + createdAt_DESC +} + +type FinancialBeingsPreviousValues { + id: ID! + type: FBType + kind: FBKind + updatedAt: DateTime! + createdAt: DateTime! +} + +type FinancialBeingsSubscriptionPayload { + mutation: MutationType! + node: FinancialBeings + updatedFields: [String!] + previousValues: FinancialBeingsPreviousValues +} + +input FinancialBeingsSubscriptionWhereInput { + """Logical AND on all given filters.""" + AND: [FinancialBeingsSubscriptionWhereInput!] + + """Logical OR on all given filters.""" + OR: [FinancialBeingsSubscriptionWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [FinancialBeingsSubscriptionWhereInput!] + + """ + The subscription event gets dispatched when it's listed in mutation_in + """ + mutation_in: [MutationType!] + + """ + The subscription event gets only dispatched when one of the updated fields names is included in this list + """ + updatedFields_contains: String + + """ + The subscription event gets only dispatched when all of the field names included in this list have been updated + """ + updatedFields_contains_every: [String!] + + """ + The subscription event gets only dispatched when some of the field names included in this list have been updated + """ + updatedFields_contains_some: [String!] + node: FinancialBeingsWhereInput +} + +input FinancialBeingsUpdateInput { + type: FBType + kind: FBKind + team: TeamUpdateOneWithoutFbInput + status: FBStatusUpdateManyInput +} + +input FinancialBeingsUpdateManyWithoutTeamInput { + create: [FinancialBeingsCreateWithoutTeamInput!] + connect: [FinancialBeingsWhereUniqueInput!] + disconnect: [FinancialBeingsWhereUniqueInput!] + delete: [FinancialBeingsWhereUniqueInput!] + update: [FinancialBeingsUpdateWithWhereUniqueWithoutTeamInput!] + upsert: [FinancialBeingsUpsertWithWhereUniqueWithoutTeamInput!] +} + +input FinancialBeingsUpdateWithoutTeamDataInput { + type: FBType + kind: FBKind + status: FBStatusUpdateManyInput +} + +input FinancialBeingsUpdateWithWhereUniqueWithoutTeamInput { + where: FinancialBeingsWhereUniqueInput! + data: FinancialBeingsUpdateWithoutTeamDataInput! +} + +input FinancialBeingsUpsertWithWhereUniqueWithoutTeamInput { + where: FinancialBeingsWhereUniqueInput! + update: FinancialBeingsUpdateWithoutTeamDataInput! + create: FinancialBeingsCreateWithoutTeamInput! +} + +input FinancialBeingsWhereInput { + """Logical AND on all given filters.""" + AND: [FinancialBeingsWhereInput!] + + """Logical OR on all given filters.""" + OR: [FinancialBeingsWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [FinancialBeingsWhereInput!] + id: ID + + """All values that are not equal to given value.""" + id_not: ID + + """All values that are contained in given list.""" + id_in: [ID!] + + """All values that are not contained in given list.""" + id_not_in: [ID!] + + """All values less than the given value.""" + id_lt: ID + + """All values less than or equal the given value.""" + id_lte: ID + + """All values greater than the given value.""" + id_gt: ID + + """All values greater than or equal the given value.""" + id_gte: ID + + """All values containing the given string.""" + id_contains: ID + + """All values not containing the given string.""" + id_not_contains: ID + + """All values starting with the given string.""" + id_starts_with: ID + + """All values not starting with the given string.""" + id_not_starts_with: ID + + """All values ending with the given string.""" + id_ends_with: ID + + """All values not ending with the given string.""" + id_not_ends_with: ID + type: FBType + + """All values that are not equal to given value.""" + type_not: FBType + + """All values that are contained in given list.""" + type_in: [FBType!] + + """All values that are not contained in given list.""" + type_not_in: [FBType!] + kind: FBKind + + """All values that are not equal to given value.""" + kind_not: FBKind + + """All values that are contained in given list.""" + kind_in: [FBKind!] + + """All values that are not contained in given list.""" + kind_not_in: [FBKind!] + updatedAt: DateTime + + """All values that are not equal to given value.""" + updatedAt_not: DateTime + + """All values that are contained in given list.""" + updatedAt_in: [DateTime!] + + """All values that are not contained in given list.""" + updatedAt_not_in: [DateTime!] + + """All values less than the given value.""" + updatedAt_lt: DateTime + + """All values less than or equal the given value.""" + updatedAt_lte: DateTime + + """All values greater than the given value.""" + updatedAt_gt: DateTime + + """All values greater than or equal the given value.""" + updatedAt_gte: DateTime + createdAt: DateTime + + """All values that are not equal to given value.""" + createdAt_not: DateTime + + """All values that are contained in given list.""" + createdAt_in: [DateTime!] + + """All values that are not contained in given list.""" + createdAt_not_in: [DateTime!] + + """All values less than the given value.""" + createdAt_lt: DateTime + + """All values less than or equal the given value.""" + createdAt_lte: DateTime + + """All values greater than the given value.""" + createdAt_gt: DateTime + + """All values greater than or equal the given value.""" + createdAt_gte: DateTime + team: TeamWhereInput + status_every: FBStatusWhereInput + status_some: FBStatusWhereInput + status_none: FBStatusWhereInput +} + +input FinancialBeingsWhereUniqueInput { + id: ID +} + +""" +The `Long` scalar type represents non-fractional signed whole numeric values. +Long can represent values between -(2^63) and 2^63 - 1. +""" +scalar Long + +type Member implements Node { + id: ID! + alias: String + team(where: TeamMembersWhereInput): TeamMembers + authId: String! + visible: Boolean! + createdAt: DateTime! +} + +"""A connection to a list of items.""" +type MemberConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [MemberEdge]! + aggregate: AggregateMember! +} + +input MemberCreateInput { + alias: String + authId: String! + visible: Boolean + team: TeamMembersCreateOneWithoutMemberInput +} + +input MemberCreateOneWithoutTeamInput { + create: MemberCreateWithoutTeamInput + connect: MemberWhereUniqueInput +} + +input MemberCreateWithoutTeamInput { + alias: String + authId: String! + visible: Boolean +} + +"""An edge in a connection.""" +type MemberEdge { + """The item at the end of the edge.""" + node: Member! + + """A cursor for use in pagination.""" + cursor: String! +} + +enum MemberOrderByInput { + id_ASC + id_DESC + alias_ASC + alias_DESC + authId_ASC + authId_DESC + visible_ASC + visible_DESC + createdAt_ASC + createdAt_DESC + updatedAt_ASC + updatedAt_DESC +} + +type MemberPreviousValues { + id: ID! + alias: String + authId: String! + visible: Boolean! + createdAt: DateTime! +} + +type MemberStatus { + status: Status + reason: String + createdAt: DateTime! +} + +"""A connection to a list of items.""" +type MemberStatusConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [MemberStatusEdge]! + aggregate: AggregateMemberStatus! +} + +input MemberStatusCreateInput { + status: Status + reason: String +} + +input MemberStatusCreateManyInput { + create: [MemberStatusCreateInput!] +} + +"""An edge in a connection.""" +type MemberStatusEdge { + """The item at the end of the edge.""" + node: MemberStatus! + + """A cursor for use in pagination.""" + cursor: String! +} + +enum MemberStatusOrderByInput { + status_ASC + status_DESC + reason_ASC + reason_DESC + createdAt_ASC + createdAt_DESC + id_ASC + id_DESC + updatedAt_ASC + updatedAt_DESC +} + +type MemberStatusPreviousValues { + status: Status + reason: String + createdAt: DateTime! +} + +type MemberStatusSubscriptionPayload { + mutation: MutationType! + node: MemberStatus + updatedFields: [String!] + previousValues: MemberStatusPreviousValues +} + +input MemberStatusSubscriptionWhereInput { + """Logical AND on all given filters.""" + AND: [MemberStatusSubscriptionWhereInput!] + + """Logical OR on all given filters.""" + OR: [MemberStatusSubscriptionWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [MemberStatusSubscriptionWhereInput!] + + """ + The subscription event gets dispatched when it's listed in mutation_in + """ + mutation_in: [MutationType!] + + """ + The subscription event gets only dispatched when one of the updated fields names is included in this list + """ + updatedFields_contains: String + + """ + The subscription event gets only dispatched when all of the field names included in this list have been updated + """ + updatedFields_contains_every: [String!] + + """ + The subscription event gets only dispatched when some of the field names included in this list have been updated + """ + updatedFields_contains_some: [String!] + node: MemberStatusWhereInput +} + +input MemberStatusUpdateInput { + status: Status + reason: String +} + +input MemberStatusUpdateManyInput { + create: [MemberStatusCreateInput!] +} + +input MemberStatusWhereInput { + """Logical AND on all given filters.""" + AND: [MemberStatusWhereInput!] + + """Logical OR on all given filters.""" + OR: [MemberStatusWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [MemberStatusWhereInput!] + status: Status + + """All values that are not equal to given value.""" + status_not: Status + + """All values that are contained in given list.""" + status_in: [Status!] + + """All values that are not contained in given list.""" + status_not_in: [Status!] + reason: String + + """All values that are not equal to given value.""" + reason_not: String + + """All values that are contained in given list.""" + reason_in: [String!] + + """All values that are not contained in given list.""" + reason_not_in: [String!] + + """All values less than the given value.""" + reason_lt: String + + """All values less than or equal the given value.""" + reason_lte: String + + """All values greater than the given value.""" + reason_gt: String + + """All values greater than or equal the given value.""" + reason_gte: String + + """All values containing the given string.""" + reason_contains: String + + """All values not containing the given string.""" + reason_not_contains: String + + """All values starting with the given string.""" + reason_starts_with: String + + """All values not starting with the given string.""" + reason_not_starts_with: String + + """All values ending with the given string.""" + reason_ends_with: String + + """All values not ending with the given string.""" + reason_not_ends_with: String + createdAt: DateTime + + """All values that are not equal to given value.""" + createdAt_not: DateTime + + """All values that are contained in given list.""" + createdAt_in: [DateTime!] + + """All values that are not contained in given list.""" + createdAt_not_in: [DateTime!] + + """All values less than the given value.""" + createdAt_lt: DateTime + + """All values less than or equal the given value.""" + createdAt_lte: DateTime + + """All values greater than the given value.""" + createdAt_gt: DateTime + + """All values greater than or equal the given value.""" + createdAt_gte: DateTime +} + +type MemberSubscriptionPayload { + mutation: MutationType! + node: Member + updatedFields: [String!] + previousValues: MemberPreviousValues +} + +input MemberSubscriptionWhereInput { + """Logical AND on all given filters.""" + AND: [MemberSubscriptionWhereInput!] + + """Logical OR on all given filters.""" + OR: [MemberSubscriptionWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [MemberSubscriptionWhereInput!] + + """ + The subscription event gets dispatched when it's listed in mutation_in + """ + mutation_in: [MutationType!] + + """ + The subscription event gets only dispatched when one of the updated fields names is included in this list + """ + updatedFields_contains: String + + """ + The subscription event gets only dispatched when all of the field names included in this list have been updated + """ + updatedFields_contains_every: [String!] + + """ + The subscription event gets only dispatched when some of the field names included in this list have been updated + """ + updatedFields_contains_some: [String!] + node: MemberWhereInput +} + +input MemberUpdateInput { + alias: String + authId: String + visible: Boolean + team: TeamMembersUpdateOneWithoutMemberInput +} + +input MemberUpdateOneWithoutTeamInput { + create: MemberCreateWithoutTeamInput + connect: MemberWhereUniqueInput + disconnect: Boolean + delete: Boolean + update: MemberUpdateWithoutTeamDataInput + upsert: MemberUpsertWithoutTeamInput +} + +input MemberUpdateWithoutTeamDataInput { + alias: String + authId: String + visible: Boolean +} + +input MemberUpsertWithoutTeamInput { + update: MemberUpdateWithoutTeamDataInput! + create: MemberCreateWithoutTeamInput! +} + +input MemberWhereInput { + """Logical AND on all given filters.""" + AND: [MemberWhereInput!] + + """Logical OR on all given filters.""" + OR: [MemberWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [MemberWhereInput!] + id: ID + + """All values that are not equal to given value.""" + id_not: ID + + """All values that are contained in given list.""" + id_in: [ID!] + + """All values that are not contained in given list.""" + id_not_in: [ID!] + + """All values less than the given value.""" + id_lt: ID + + """All values less than or equal the given value.""" + id_lte: ID + + """All values greater than the given value.""" + id_gt: ID + + """All values greater than or equal the given value.""" + id_gte: ID + + """All values containing the given string.""" + id_contains: ID + + """All values not containing the given string.""" + id_not_contains: ID + + """All values starting with the given string.""" + id_starts_with: ID + + """All values not starting with the given string.""" + id_not_starts_with: ID + + """All values ending with the given string.""" + id_ends_with: ID + + """All values not ending with the given string.""" + id_not_ends_with: ID + alias: String + + """All values that are not equal to given value.""" + alias_not: String + + """All values that are contained in given list.""" + alias_in: [String!] + + """All values that are not contained in given list.""" + alias_not_in: [String!] + + """All values less than the given value.""" + alias_lt: String + + """All values less than or equal the given value.""" + alias_lte: String + + """All values greater than the given value.""" + alias_gt: String + + """All values greater than or equal the given value.""" + alias_gte: String + + """All values containing the given string.""" + alias_contains: String + + """All values not containing the given string.""" + alias_not_contains: String + + """All values starting with the given string.""" + alias_starts_with: String + + """All values not starting with the given string.""" + alias_not_starts_with: String + + """All values ending with the given string.""" + alias_ends_with: String + + """All values not ending with the given string.""" + alias_not_ends_with: String + authId: String + + """All values that are not equal to given value.""" + authId_not: String + + """All values that are contained in given list.""" + authId_in: [String!] + + """All values that are not contained in given list.""" + authId_not_in: [String!] + + """All values less than the given value.""" + authId_lt: String + + """All values less than or equal the given value.""" + authId_lte: String + + """All values greater than the given value.""" + authId_gt: String + + """All values greater than or equal the given value.""" + authId_gte: String + + """All values containing the given string.""" + authId_contains: String + + """All values not containing the given string.""" + authId_not_contains: String + + """All values starting with the given string.""" + authId_starts_with: String + + """All values not starting with the given string.""" + authId_not_starts_with: String + + """All values ending with the given string.""" + authId_ends_with: String + + """All values not ending with the given string.""" + authId_not_ends_with: String + visible: Boolean + + """All values that are not equal to given value.""" + visible_not: Boolean + createdAt: DateTime + + """All values that are not equal to given value.""" + createdAt_not: DateTime + + """All values that are contained in given list.""" + createdAt_in: [DateTime!] + + """All values that are not contained in given list.""" + createdAt_not_in: [DateTime!] + + """All values less than the given value.""" + createdAt_lt: DateTime + + """All values less than or equal the given value.""" + createdAt_lte: DateTime + + """All values greater than the given value.""" + createdAt_gt: DateTime + + """All values greater than or equal the given value.""" + createdAt_gte: DateTime + team: TeamMembersWhereInput +} + +input MemberWhereUniqueInput { + id: ID + authId: String +} + +type Mutation { + createTeam(data: TeamCreateInput!): Team! + createTeamMembers(data: TeamMembersCreateInput!): TeamMembers! + createMember(data: MemberCreateInput!): Member! + createFinancialBeings(data: FinancialBeingsCreateInput!): FinancialBeings! + createTeamProfile(data: TeamProfileCreateInput!): TeamProfile! + createWallet(data: WalletCreateInput!): Wallet! + createFBStatus(data: FBStatusCreateInput!): FBStatus! + createTeamStatus(data: TeamStatusCreateInput!): TeamStatus! + createMemberStatus(data: MemberStatusCreateInput!): MemberStatus! + updateTeam(data: TeamUpdateInput!, where: TeamWhereUniqueInput!): Team + updateMember(data: MemberUpdateInput!, where: MemberWhereUniqueInput!): Member + updateFinancialBeings(data: FinancialBeingsUpdateInput!, where: FinancialBeingsWhereUniqueInput!): FinancialBeings + deleteTeam(where: TeamWhereUniqueInput!): Team + deleteMember(where: MemberWhereUniqueInput!): Member + deleteFinancialBeings(where: FinancialBeingsWhereUniqueInput!): FinancialBeings + upsertTeam(where: TeamWhereUniqueInput!, create: TeamCreateInput!, update: TeamUpdateInput!): Team! + upsertMember(where: MemberWhereUniqueInput!, create: MemberCreateInput!, update: MemberUpdateInput!): Member! + upsertFinancialBeings(where: FinancialBeingsWhereUniqueInput!, create: FinancialBeingsCreateInput!, update: FinancialBeingsUpdateInput!): FinancialBeings! + 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! + updateManyFBStatuses(data: FBStatusUpdateInput!, where: FBStatusWhereInput): BatchPayload! + updateManyTeamStatuses(data: TeamStatusUpdateInput!, where: TeamStatusWhereInput): BatchPayload! + updateManyMemberStatuses(data: MemberStatusUpdateInput!, where: MemberStatusWhereInput): BatchPayload! + deleteManyTeams(where: TeamWhereInput): BatchPayload! + deleteManyTeamMemberses(where: TeamMembersWhereInput): BatchPayload! + deleteManyMembers(where: MemberWhereInput): BatchPayload! + deleteManyFinancialBeingses(where: FinancialBeingsWhereInput): BatchPayload! + deleteManyTeamProfiles(where: TeamProfileWhereInput): BatchPayload! + deleteManyWallets(where: WalletWhereInput): BatchPayload! + deleteManyFBStatuses(where: FBStatusWhereInput): BatchPayload! + deleteManyTeamStatuses(where: TeamStatusWhereInput): BatchPayload! + deleteManyMemberStatuses(where: MemberStatusWhereInput): BatchPayload! +} + +enum MutationType { + CREATED + UPDATED + DELETED +} + +"""An object with an ID""" +interface Node { + """The id of the object.""" + id: ID! +} + +"""Information about pagination in a connection.""" +type PageInfo { + """When paginating forwards, are there more items?""" + hasNextPage: Boolean! + + """When paginating backwards, are there more items?""" + hasPreviousPage: Boolean! + + """When paginating backwards, the cursor to continue.""" + startCursor: String + + """When paginating forwards, the cursor to continue.""" + endCursor: String +} + +type Query { + teams(where: TeamWhereInput, orderBy: TeamOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Team]! + teamMemberses(where: TeamMembersWhereInput, orderBy: TeamMembersOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [TeamMembers]! + members(where: MemberWhereInput, orderBy: MemberOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Member]! + financialBeingses(where: FinancialBeingsWhereInput, orderBy: FinancialBeingsOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [FinancialBeings]! + teamProfiles(where: TeamProfileWhereInput, orderBy: TeamProfileOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [TeamProfile]! + wallets(where: WalletWhereInput, orderBy: WalletOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Wallet]! + fBStatuses(where: FBStatusWhereInput, orderBy: FBStatusOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [FBStatus]! + teamStatuses(where: TeamStatusWhereInput, orderBy: TeamStatusOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [TeamStatus]! + memberStatuses(where: MemberStatusWhereInput, orderBy: MemberStatusOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [MemberStatus]! + team(where: TeamWhereUniqueInput!): Team + member(where: MemberWhereUniqueInput!): Member + financialBeings(where: FinancialBeingsWhereUniqueInput!): FinancialBeings + teamsConnection(where: TeamWhereInput, orderBy: TeamOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): TeamConnection! + teamMembersesConnection(where: TeamMembersWhereInput, orderBy: TeamMembersOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): TeamMembersConnection! + membersConnection(where: MemberWhereInput, orderBy: MemberOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): MemberConnection! + financialBeingsesConnection(where: FinancialBeingsWhereInput, orderBy: FinancialBeingsOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): FinancialBeingsConnection! + teamProfilesConnection(where: TeamProfileWhereInput, orderBy: TeamProfileOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): TeamProfileConnection! + walletsConnection(where: WalletWhereInput, orderBy: WalletOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): WalletConnection! + fBStatusesConnection(where: FBStatusWhereInput, orderBy: FBStatusOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): FBStatusConnection! + teamStatusesConnection(where: TeamStatusWhereInput, orderBy: TeamStatusOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): TeamStatusConnection! + memberStatusesConnection(where: MemberStatusWhereInput, orderBy: MemberStatusOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): MemberStatusConnection! + + """Fetches an object given its ID""" + node( + """The ID of an object""" + id: ID! + ): Node +} + +enum Role { + OWNER + ADMIN + MEMBER +} + +enum Status { + ACTIVE + INACTIVE + APPLY + INVITE +} + +type Subscription { + team(where: TeamSubscriptionWhereInput): TeamSubscriptionPayload + teamMembers(where: TeamMembersSubscriptionWhereInput): TeamMembersSubscriptionPayload + member(where: MemberSubscriptionWhereInput): MemberSubscriptionPayload + financialBeings(where: FinancialBeingsSubscriptionWhereInput): FinancialBeingsSubscriptionPayload + teamProfile(where: TeamProfileSubscriptionWhereInput): TeamProfileSubscriptionPayload + wallet(where: WalletSubscriptionWhereInput): WalletSubscriptionPayload + fBStatus(where: FBStatusSubscriptionWhereInput): FBStatusSubscriptionPayload + teamStatus(where: TeamStatusSubscriptionWhereInput): TeamStatusSubscriptionPayload + memberStatus(where: MemberStatusSubscriptionWhereInput): MemberStatusSubscriptionPayload +} + +type Team implements Node { + id: ID! + name: String! + slug: String! + profile(where: TeamProfileWhereInput): TeamProfile + members(where: TeamMembersWhereInput, orderBy: TeamMembersOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [TeamMembers!] + owner: String! + wallet(where: WalletWhereInput): 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! +} + +"""A connection to a list of items.""" +type TeamConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [TeamEdge]! + aggregate: AggregateTeam! +} + +input TeamCreateInput { + name: String! + slug: String! + owner: String! + profile: TeamProfileCreateOneInput + members: TeamMembersCreateManyWithoutTeamInput + wallet: WalletCreateOneInput + fb: FinancialBeingsCreateManyWithoutTeamInput + status: TeamStatusCreateManyInput +} + +input TeamCreateOneWithoutFbInput { + create: TeamCreateWithoutFbInput + connect: TeamWhereUniqueInput +} + +input TeamCreateOneWithoutMembersInput { + create: TeamCreateWithoutMembersInput + connect: TeamWhereUniqueInput +} + +input TeamCreateWithoutFbInput { + name: String! + slug: String! + owner: String! + profile: TeamProfileCreateOneInput + members: TeamMembersCreateManyWithoutTeamInput + wallet: WalletCreateOneInput + status: TeamStatusCreateManyInput +} + +input TeamCreateWithoutMembersInput { + name: String! + slug: String! + owner: String! + profile: TeamProfileCreateOneInput + wallet: WalletCreateOneInput + fb: FinancialBeingsCreateManyWithoutTeamInput + status: TeamStatusCreateManyInput +} + +"""An edge in a connection.""" +type TeamEdge { + """The item at the end of the edge.""" + node: Team! + + """A cursor for use in pagination.""" + cursor: String! +} + +type TeamMembers { + member(where: MemberWhereInput): Member + team(where: TeamWhereInput): Team + role: Role + status(where: MemberStatusWhereInput, orderBy: MemberStatusOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [MemberStatus!] + updatedAt: DateTime! +} + +"""A connection to a list of items.""" +type TeamMembersConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [TeamMembersEdge]! + aggregate: AggregateTeamMembers! +} + +input TeamMembersCreateInput { + role: Role + member: MemberCreateOneWithoutTeamInput + team: TeamCreateOneWithoutMembersInput + status: MemberStatusCreateManyInput +} + +input TeamMembersCreateManyWithoutTeamInput { + create: [TeamMembersCreateWithoutTeamInput!] +} + +input TeamMembersCreateOneWithoutMemberInput { + create: TeamMembersCreateWithoutMemberInput +} + +input TeamMembersCreateWithoutMemberInput { + role: Role + team: TeamCreateOneWithoutMembersInput + status: MemberStatusCreateManyInput +} + +input TeamMembersCreateWithoutTeamInput { + role: Role + member: MemberCreateOneWithoutTeamInput + status: MemberStatusCreateManyInput +} + +"""An edge in a connection.""" +type TeamMembersEdge { + """The item at the end of the edge.""" + node: TeamMembers! + + """A cursor for use in pagination.""" + cursor: String! +} + +enum TeamMembersOrderByInput { + role_ASC + role_DESC + updatedAt_ASC + updatedAt_DESC + id_ASC + id_DESC + createdAt_ASC + createdAt_DESC +} + +type TeamMembersPreviousValues { + role: Role + updatedAt: DateTime! +} + +type TeamMembersSubscriptionPayload { + mutation: MutationType! + node: TeamMembers + updatedFields: [String!] + previousValues: TeamMembersPreviousValues +} + +input TeamMembersSubscriptionWhereInput { + """Logical AND on all given filters.""" + AND: [TeamMembersSubscriptionWhereInput!] + + """Logical OR on all given filters.""" + OR: [TeamMembersSubscriptionWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [TeamMembersSubscriptionWhereInput!] + + """ + The subscription event gets dispatched when it's listed in mutation_in + """ + mutation_in: [MutationType!] + + """ + The subscription event gets only dispatched when one of the updated fields names is included in this list + """ + updatedFields_contains: String + + """ + The subscription event gets only dispatched when all of the field names included in this list have been updated + """ + updatedFields_contains_every: [String!] + + """ + The subscription event gets only dispatched when some of the field names included in this list have been updated + """ + updatedFields_contains_some: [String!] + node: TeamMembersWhereInput +} + +input TeamMembersUpdateInput { + role: Role + member: MemberUpdateOneWithoutTeamInput + team: TeamUpdateOneWithoutMembersInput + status: MemberStatusUpdateManyInput +} + +input TeamMembersUpdateManyWithoutTeamInput { + create: [TeamMembersCreateWithoutTeamInput!] +} + +input TeamMembersUpdateOneWithoutMemberInput { + create: TeamMembersCreateWithoutMemberInput + disconnect: Boolean + delete: Boolean + update: TeamMembersUpdateWithoutMemberDataInput + upsert: TeamMembersUpsertWithoutMemberInput +} + +input TeamMembersUpdateWithoutMemberDataInput { + role: Role + team: TeamUpdateOneWithoutMembersInput + status: MemberStatusUpdateManyInput +} + +input TeamMembersUpsertWithoutMemberInput { + update: TeamMembersUpdateWithoutMemberDataInput! + create: TeamMembersCreateWithoutMemberInput! +} + +input TeamMembersWhereInput { + """Logical AND on all given filters.""" + AND: [TeamMembersWhereInput!] + + """Logical OR on all given filters.""" + OR: [TeamMembersWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [TeamMembersWhereInput!] + role: Role + + """All values that are not equal to given value.""" + role_not: Role + + """All values that are contained in given list.""" + role_in: [Role!] + + """All values that are not contained in given list.""" + role_not_in: [Role!] + updatedAt: DateTime + + """All values that are not equal to given value.""" + updatedAt_not: DateTime + + """All values that are contained in given list.""" + updatedAt_in: [DateTime!] + + """All values that are not contained in given list.""" + updatedAt_not_in: [DateTime!] + + """All values less than the given value.""" + updatedAt_lt: DateTime + + """All values less than or equal the given value.""" + updatedAt_lte: DateTime + + """All values greater than the given value.""" + updatedAt_gt: DateTime + + """All values greater than or equal the given value.""" + updatedAt_gte: DateTime + member: MemberWhereInput + team: TeamWhereInput + status_every: MemberStatusWhereInput + status_some: MemberStatusWhereInput + status_none: MemberStatusWhereInput +} + +enum TeamOrderByInput { + id_ASC + id_DESC + name_ASC + name_DESC + slug_ASC + slug_DESC + owner_ASC + owner_DESC + createdAt_ASC + createdAt_DESC + updatedAt_ASC + updatedAt_DESC +} + +type TeamPreviousValues { + id: ID! + name: String! + slug: String! + owner: String! + createdAt: DateTime! +} + +type TeamProfile { + description: String + motto: String + avatar: String + updatedAt: DateTime! +} + +"""A connection to a list of items.""" +type TeamProfileConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [TeamProfileEdge]! + aggregate: AggregateTeamProfile! +} + +input TeamProfileCreateInput { + description: String + motto: String + avatar: String +} + +input TeamProfileCreateOneInput { + create: TeamProfileCreateInput +} + +"""An edge in a connection.""" +type TeamProfileEdge { + """The item at the end of the edge.""" + node: TeamProfile! + + """A cursor for use in pagination.""" + cursor: String! +} + +enum TeamProfileOrderByInput { + description_ASC + description_DESC + motto_ASC + motto_DESC + avatar_ASC + avatar_DESC + updatedAt_ASC + updatedAt_DESC + id_ASC + id_DESC + createdAt_ASC + createdAt_DESC +} + +type TeamProfilePreviousValues { + description: String + motto: String + avatar: String + updatedAt: DateTime! +} + +type TeamProfileSubscriptionPayload { + mutation: MutationType! + node: TeamProfile + updatedFields: [String!] + previousValues: TeamProfilePreviousValues +} + +input TeamProfileSubscriptionWhereInput { + """Logical AND on all given filters.""" + AND: [TeamProfileSubscriptionWhereInput!] + + """Logical OR on all given filters.""" + OR: [TeamProfileSubscriptionWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [TeamProfileSubscriptionWhereInput!] + + """ + The subscription event gets dispatched when it's listed in mutation_in + """ + mutation_in: [MutationType!] + + """ + The subscription event gets only dispatched when one of the updated fields names is included in this list + """ + updatedFields_contains: String + + """ + The subscription event gets only dispatched when all of the field names included in this list have been updated + """ + updatedFields_contains_every: [String!] + + """ + The subscription event gets only dispatched when some of the field names included in this list have been updated + """ + updatedFields_contains_some: [String!] + node: TeamProfileWhereInput +} + +input TeamProfileUpdateDataInput { + description: String + motto: String + avatar: String +} + +input TeamProfileUpdateInput { + description: String + motto: String + avatar: String +} + +input TeamProfileUpdateOneInput { + create: TeamProfileCreateInput + disconnect: Boolean + delete: Boolean + update: TeamProfileUpdateDataInput + upsert: TeamProfileUpsertNestedInput +} + +input TeamProfileUpsertNestedInput { + update: TeamProfileUpdateDataInput! + create: TeamProfileCreateInput! +} + +input TeamProfileWhereInput { + """Logical AND on all given filters.""" + AND: [TeamProfileWhereInput!] + + """Logical OR on all given filters.""" + OR: [TeamProfileWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [TeamProfileWhereInput!] + description: String + + """All values that are not equal to given value.""" + description_not: String + + """All values that are contained in given list.""" + description_in: [String!] + + """All values that are not contained in given list.""" + description_not_in: [String!] + + """All values less than the given value.""" + description_lt: String + + """All values less than or equal the given value.""" + description_lte: String + + """All values greater than the given value.""" + description_gt: String + + """All values greater than or equal the given value.""" + description_gte: String + + """All values containing the given string.""" + description_contains: String + + """All values not containing the given string.""" + description_not_contains: String + + """All values starting with the given string.""" + description_starts_with: String + + """All values not starting with the given string.""" + description_not_starts_with: String + + """All values ending with the given string.""" + description_ends_with: String + + """All values not ending with the given string.""" + description_not_ends_with: String + motto: String + + """All values that are not equal to given value.""" + motto_not: String + + """All values that are contained in given list.""" + motto_in: [String!] + + """All values that are not contained in given list.""" + motto_not_in: [String!] + + """All values less than the given value.""" + motto_lt: String + + """All values less than or equal the given value.""" + motto_lte: String + + """All values greater than the given value.""" + motto_gt: String + + """All values greater than or equal the given value.""" + motto_gte: String + + """All values containing the given string.""" + motto_contains: String + + """All values not containing the given string.""" + motto_not_contains: String + + """All values starting with the given string.""" + motto_starts_with: String + + """All values not starting with the given string.""" + motto_not_starts_with: String + + """All values ending with the given string.""" + motto_ends_with: String + + """All values not ending with the given string.""" + motto_not_ends_with: String + avatar: String + + """All values that are not equal to given value.""" + avatar_not: String + + """All values that are contained in given list.""" + avatar_in: [String!] + + """All values that are not contained in given list.""" + avatar_not_in: [String!] + + """All values less than the given value.""" + avatar_lt: String + + """All values less than or equal the given value.""" + avatar_lte: String + + """All values greater than the given value.""" + avatar_gt: String + + """All values greater than or equal the given value.""" + avatar_gte: String + + """All values containing the given string.""" + avatar_contains: String + + """All values not containing the given string.""" + avatar_not_contains: String + + """All values starting with the given string.""" + avatar_starts_with: String + + """All values not starting with the given string.""" + avatar_not_starts_with: String + + """All values ending with the given string.""" + avatar_ends_with: String + + """All values not ending with the given string.""" + avatar_not_ends_with: String + updatedAt: DateTime + + """All values that are not equal to given value.""" + updatedAt_not: DateTime + + """All values that are contained in given list.""" + updatedAt_in: [DateTime!] + + """All values that are not contained in given list.""" + updatedAt_not_in: [DateTime!] + + """All values less than the given value.""" + updatedAt_lt: DateTime + + """All values less than or equal the given value.""" + updatedAt_lte: DateTime + + """All values greater than the given value.""" + updatedAt_gt: DateTime + + """All values greater than or equal the given value.""" + updatedAt_gte: DateTime +} + +type TeamStatus { + status: Status + reason: String + createdAt: DateTime! +} + +"""A connection to a list of items.""" +type TeamStatusConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [TeamStatusEdge]! + aggregate: AggregateTeamStatus! +} + +input TeamStatusCreateInput { + status: Status + reason: String +} + +input TeamStatusCreateManyInput { + create: [TeamStatusCreateInput!] +} + +"""An edge in a connection.""" +type TeamStatusEdge { + """The item at the end of the edge.""" + node: TeamStatus! + + """A cursor for use in pagination.""" + cursor: String! +} + +enum TeamStatusOrderByInput { + status_ASC + status_DESC + reason_ASC + reason_DESC + createdAt_ASC + createdAt_DESC + id_ASC + id_DESC + updatedAt_ASC + updatedAt_DESC +} + +type TeamStatusPreviousValues { + status: Status + reason: String + createdAt: DateTime! +} + +type TeamStatusSubscriptionPayload { + mutation: MutationType! + node: TeamStatus + updatedFields: [String!] + previousValues: TeamStatusPreviousValues +} + +input TeamStatusSubscriptionWhereInput { + """Logical AND on all given filters.""" + AND: [TeamStatusSubscriptionWhereInput!] + + """Logical OR on all given filters.""" + OR: [TeamStatusSubscriptionWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [TeamStatusSubscriptionWhereInput!] + + """ + The subscription event gets dispatched when it's listed in mutation_in + """ + mutation_in: [MutationType!] + + """ + The subscription event gets only dispatched when one of the updated fields names is included in this list + """ + updatedFields_contains: String + + """ + The subscription event gets only dispatched when all of the field names included in this list have been updated + """ + updatedFields_contains_every: [String!] + + """ + The subscription event gets only dispatched when some of the field names included in this list have been updated + """ + updatedFields_contains_some: [String!] + node: TeamStatusWhereInput +} + +input TeamStatusUpdateInput { + status: Status + reason: String +} + +input TeamStatusUpdateManyInput { + create: [TeamStatusCreateInput!] +} + +input TeamStatusWhereInput { + """Logical AND on all given filters.""" + AND: [TeamStatusWhereInput!] + + """Logical OR on all given filters.""" + OR: [TeamStatusWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [TeamStatusWhereInput!] + status: Status + + """All values that are not equal to given value.""" + status_not: Status + + """All values that are contained in given list.""" + status_in: [Status!] + + """All values that are not contained in given list.""" + status_not_in: [Status!] + reason: String + + """All values that are not equal to given value.""" + reason_not: String + + """All values that are contained in given list.""" + reason_in: [String!] + + """All values that are not contained in given list.""" + reason_not_in: [String!] + + """All values less than the given value.""" + reason_lt: String + + """All values less than or equal the given value.""" + reason_lte: String + + """All values greater than the given value.""" + reason_gt: String + + """All values greater than or equal the given value.""" + reason_gte: String + + """All values containing the given string.""" + reason_contains: String + + """All values not containing the given string.""" + reason_not_contains: String + + """All values starting with the given string.""" + reason_starts_with: String + + """All values not starting with the given string.""" + reason_not_starts_with: String + + """All values ending with the given string.""" + reason_ends_with: String + + """All values not ending with the given string.""" + reason_not_ends_with: String + createdAt: DateTime + + """All values that are not equal to given value.""" + createdAt_not: DateTime + + """All values that are contained in given list.""" + createdAt_in: [DateTime!] + + """All values that are not contained in given list.""" + createdAt_not_in: [DateTime!] + + """All values less than the given value.""" + createdAt_lt: DateTime + + """All values less than or equal the given value.""" + createdAt_lte: DateTime + + """All values greater than the given value.""" + createdAt_gt: DateTime + + """All values greater than or equal the given value.""" + createdAt_gte: DateTime +} + +type TeamSubscriptionPayload { + mutation: MutationType! + node: Team + updatedFields: [String!] + previousValues: TeamPreviousValues +} + +input TeamSubscriptionWhereInput { + """Logical AND on all given filters.""" + AND: [TeamSubscriptionWhereInput!] + + """Logical OR on all given filters.""" + OR: [TeamSubscriptionWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [TeamSubscriptionWhereInput!] + + """ + The subscription event gets dispatched when it's listed in mutation_in + """ + mutation_in: [MutationType!] + + """ + The subscription event gets only dispatched when one of the updated fields names is included in this list + """ + updatedFields_contains: String + + """ + The subscription event gets only dispatched when all of the field names included in this list have been updated + """ + updatedFields_contains_every: [String!] + + """ + The subscription event gets only dispatched when some of the field names included in this list have been updated + """ + updatedFields_contains_some: [String!] + node: TeamWhereInput +} + +input TeamUpdateInput { + name: String + slug: String + owner: String + profile: TeamProfileUpdateOneInput + members: TeamMembersUpdateManyWithoutTeamInput + wallet: WalletUpdateOneInput + fb: FinancialBeingsUpdateManyWithoutTeamInput + status: TeamStatusUpdateManyInput +} + +input TeamUpdateOneWithoutFbInput { + create: TeamCreateWithoutFbInput + connect: TeamWhereUniqueInput + disconnect: Boolean + delete: Boolean + update: TeamUpdateWithoutFbDataInput + upsert: TeamUpsertWithoutFbInput +} + +input TeamUpdateOneWithoutMembersInput { + create: TeamCreateWithoutMembersInput + connect: TeamWhereUniqueInput + disconnect: Boolean + delete: Boolean + update: TeamUpdateWithoutMembersDataInput + upsert: TeamUpsertWithoutMembersInput +} + +input TeamUpdateWithoutFbDataInput { + name: String + slug: String + owner: String + profile: TeamProfileUpdateOneInput + members: TeamMembersUpdateManyWithoutTeamInput + wallet: WalletUpdateOneInput + status: TeamStatusUpdateManyInput +} + +input TeamUpdateWithoutMembersDataInput { + name: String + slug: String + owner: String + profile: TeamProfileUpdateOneInput + wallet: WalletUpdateOneInput + fb: FinancialBeingsUpdateManyWithoutTeamInput + status: TeamStatusUpdateManyInput +} + +input TeamUpsertWithoutFbInput { + update: TeamUpdateWithoutFbDataInput! + create: TeamCreateWithoutFbInput! +} + +input TeamUpsertWithoutMembersInput { + update: TeamUpdateWithoutMembersDataInput! + create: TeamCreateWithoutMembersInput! +} + +input TeamWhereInput { + """Logical AND on all given filters.""" + AND: [TeamWhereInput!] + + """Logical OR on all given filters.""" + OR: [TeamWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [TeamWhereInput!] + id: ID + + """All values that are not equal to given value.""" + id_not: ID + + """All values that are contained in given list.""" + id_in: [ID!] + + """All values that are not contained in given list.""" + id_not_in: [ID!] + + """All values less than the given value.""" + id_lt: ID + + """All values less than or equal the given value.""" + id_lte: ID + + """All values greater than the given value.""" + id_gt: ID + + """All values greater than or equal the given value.""" + id_gte: ID + + """All values containing the given string.""" + id_contains: ID + + """All values not containing the given string.""" + id_not_contains: ID + + """All values starting with the given string.""" + id_starts_with: ID + + """All values not starting with the given string.""" + id_not_starts_with: ID + + """All values ending with the given string.""" + id_ends_with: ID + + """All values not ending with the given string.""" + id_not_ends_with: ID + name: String + + """All values that are not equal to given value.""" + name_not: String + + """All values that are contained in given list.""" + name_in: [String!] + + """All values that are not contained in given list.""" + name_not_in: [String!] + + """All values less than the given value.""" + name_lt: String + + """All values less than or equal the given value.""" + name_lte: String + + """All values greater than the given value.""" + name_gt: String + + """All values greater than or equal the given value.""" + name_gte: String + + """All values containing the given string.""" + name_contains: String + + """All values not containing the given string.""" + name_not_contains: String + + """All values starting with the given string.""" + name_starts_with: String + + """All values not starting with the given string.""" + name_not_starts_with: String + + """All values ending with the given string.""" + name_ends_with: String + + """All values not ending with the given string.""" + name_not_ends_with: String + slug: String + + """All values that are not equal to given value.""" + slug_not: String + + """All values that are contained in given list.""" + slug_in: [String!] + + """All values that are not contained in given list.""" + slug_not_in: [String!] + + """All values less than the given value.""" + slug_lt: String + + """All values less than or equal the given value.""" + slug_lte: String + + """All values greater than the given value.""" + slug_gt: String + + """All values greater than or equal the given value.""" + slug_gte: String + + """All values containing the given string.""" + slug_contains: String + + """All values not containing the given string.""" + slug_not_contains: String + + """All values starting with the given string.""" + slug_starts_with: String + + """All values not starting with the given string.""" + slug_not_starts_with: String + + """All values ending with the given string.""" + slug_ends_with: String + + """All values not ending with the given string.""" + slug_not_ends_with: String + owner: String + + """All values that are not equal to given value.""" + owner_not: String + + """All values that are contained in given list.""" + owner_in: [String!] + + """All values that are not contained in given list.""" + owner_not_in: [String!] + + """All values less than the given value.""" + owner_lt: String + + """All values less than or equal the given value.""" + owner_lte: String + + """All values greater than the given value.""" + owner_gt: String + + """All values greater than or equal the given value.""" + owner_gte: String + + """All values containing the given string.""" + owner_contains: String + + """All values not containing the given string.""" + owner_not_contains: String + + """All values starting with the given string.""" + owner_starts_with: String + + """All values not starting with the given string.""" + owner_not_starts_with: String + + """All values ending with the given string.""" + owner_ends_with: String + + """All values not ending with the given string.""" + owner_not_ends_with: String + createdAt: DateTime + + """All values that are not equal to given value.""" + createdAt_not: DateTime + + """All values that are contained in given list.""" + createdAt_in: [DateTime!] + + """All values that are not contained in given list.""" + createdAt_not_in: [DateTime!] + + """All values less than the given value.""" + createdAt_lt: DateTime + + """All values less than or equal the given value.""" + createdAt_lte: DateTime + + """All values greater than the given value.""" + createdAt_gt: DateTime + + """All values greater than or equal the given value.""" + createdAt_gte: DateTime + profile: TeamProfileWhereInput + members_every: TeamMembersWhereInput + members_some: TeamMembersWhereInput + members_none: TeamMembersWhereInput + wallet: WalletWhereInput + fb_every: FinancialBeingsWhereInput + fb_some: FinancialBeingsWhereInput + fb_none: FinancialBeingsWhereInput + status_every: TeamStatusWhereInput + status_some: TeamStatusWhereInput + status_none: TeamStatusWhereInput +} + +input TeamWhereUniqueInput { + id: ID + name: String + slug: String +} + +type Wallet { + balance: Float + updatedAt: DateTime! +} + +"""A connection to a list of items.""" +type WalletConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [WalletEdge]! + aggregate: AggregateWallet! +} + +input WalletCreateInput { + balance: Float +} + +input WalletCreateOneInput { + create: WalletCreateInput +} + +"""An edge in a connection.""" +type WalletEdge { + """The item at the end of the edge.""" + node: Wallet! + + """A cursor for use in pagination.""" + cursor: String! +} + +enum WalletOrderByInput { + balance_ASC + balance_DESC + updatedAt_ASC + updatedAt_DESC + id_ASC + id_DESC + createdAt_ASC + createdAt_DESC +} + +type WalletPreviousValues { + balance: Float + updatedAt: DateTime! +} + +type WalletSubscriptionPayload { + mutation: MutationType! + node: Wallet + updatedFields: [String!] + previousValues: WalletPreviousValues +} + +input WalletSubscriptionWhereInput { + """Logical AND on all given filters.""" + AND: [WalletSubscriptionWhereInput!] + + """Logical OR on all given filters.""" + OR: [WalletSubscriptionWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [WalletSubscriptionWhereInput!] + + """ + The subscription event gets dispatched when it's listed in mutation_in + """ + mutation_in: [MutationType!] + + """ + The subscription event gets only dispatched when one of the updated fields names is included in this list + """ + updatedFields_contains: String + + """ + The subscription event gets only dispatched when all of the field names included in this list have been updated + """ + updatedFields_contains_every: [String!] + + """ + The subscription event gets only dispatched when some of the field names included in this list have been updated + """ + updatedFields_contains_some: [String!] + node: WalletWhereInput +} + +input WalletUpdateDataInput { + balance: Float +} + +input WalletUpdateInput { + balance: Float +} + +input WalletUpdateOneInput { + create: WalletCreateInput + disconnect: Boolean + delete: Boolean + update: WalletUpdateDataInput + upsert: WalletUpsertNestedInput +} + +input WalletUpsertNestedInput { + update: WalletUpdateDataInput! + create: WalletCreateInput! +} + +input WalletWhereInput { + """Logical AND on all given filters.""" + AND: [WalletWhereInput!] + + """Logical OR on all given filters.""" + OR: [WalletWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [WalletWhereInput!] + balance: Float + + """All values that are not equal to given value.""" + balance_not: Float + + """All values that are contained in given list.""" + balance_in: [Float!] + + """All values that are not contained in given list.""" + balance_not_in: [Float!] + + """All values less than the given value.""" + balance_lt: Float + + """All values less than or equal the given value.""" + balance_lte: Float + + """All values greater than the given value.""" + balance_gt: Float + + """All values greater than or equal the given value.""" + balance_gte: Float + updatedAt: DateTime + + """All values that are not equal to given value.""" + updatedAt_not: DateTime + + """All values that are contained in given list.""" + updatedAt_in: [DateTime!] + + """All values that are not contained in given list.""" + updatedAt_not_in: [DateTime!] + + """All values less than the given value.""" + updatedAt_lt: DateTime + + """All values less than or equal the given value.""" + updatedAt_lte: DateTime + + """All values greater than the given value.""" + updatedAt_gt: DateTime + + """All values greater than or equal the given value.""" + updatedAt_gte: DateTime +} diff --git a/api/src/index.js b/api/src/index.js index 33439b574..be92331cd 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -1,3 +1,4 @@ +require('dotenv').config(); const { GraphQLServer } = require('graphql-yoga') const { Prisma, @@ -8,15 +9,39 @@ const { makeExecutableSchema } = require('graphql-tools') const { importSchema } = require('graphql-import') const { checkJwt } = require('./auth/middleware/jwt') const { getMember } = require('./auth/middleware/getMember') -const validateParseIdToken = require('./auth/helpers/validate-parse-id-token') -const { directiveResolvers } = require('./auth-directives') +const { validateIdToken } = require('./auth/validateIdToken') +const { directiveResolvers } = require('./auth/authDirectives') + +const createMember = async function (ctx, info, idToken) { + console.log('createMember', idToken) + const member = await ctx.db.mutation.upsertMember({ + where: { + authId: idToken.sub, + }, + create: { + authId: idToken.sub, + alias: idToken.nickname + }, + update: { + authId: idToken.sub, + alias: idToken.nickname + } + }, info) + return member +} const ctxMember = ctx => ctx.request.member const resolvers = { Query: { - async member(parent, { auth0id }, ctx, info) { - return ctx.db.query.member({ where: { auth0id } }, info) + async member(parent, arg, ctx, info) { + console.log('member: ', parent, arg) + return ctx.db.query.member({ where: { authId: arg.authId } }, info) + }, + async currentMember(parent, args, ctx, info) { + console.log('currentMember: ', ctx.request.res.req.user) + const authId = ctx.request.res.req.user.sub + return ctx.db.query.member({ where: { authId } }, info) }, teams(parent, args, ctx, info) { return ctx.db.query.teamsConnection({}, @@ -59,7 +84,7 @@ const resolvers = { return ctx.db.query.team({ where: { name: name } }, `{ name }`) }, async teamByOwner(parent, { ownerId }, ctx, info) { - return ctx.db.query.teamsConnection({where: { owner: { auth0id: ownerId }}}, + return ctx.db.query.teamsConnection({where: { owner: { authId: ownerId }}}, `{ edges { node { @@ -72,7 +97,7 @@ const resolvers = { motto } owner { - auth0id + authId nickname visible profile { @@ -95,28 +120,27 @@ const resolvers = { }, async owner(parent, args, ctx, info) { console.log('resolver.query.owner ctx: ', ctxMember(ctx)) - return ctx.db.query.member({ where: { id: ctxMember(ctx).auth0id } }, info) + return ctx.db.query.member({ where: { id: ctxMember(ctx).authId } }, info) .catch((res) => { console.log('createTeam error: ', res) const errors = res.graphQLErrors.map((error) => { return error.message }) }) - }, - members: forwardTo('db') + } }, Mutation: { async authenticate(parent, { idToken }, ctx, info) { let memberToken = null try { - memberToken = await validateAndParseIdToken(idToken) + memberToken = await validateIdToken(idToken) console.log('authenticate.memberToken: ', await memberToken) } catch (err) { - console.log('authenticat.validateAndParseIdToken err: ', err) + console.log('authenticat.validateIdToken err: ', err) throw new Error(err.message) } - const auth0id = memberToken.sub - let member = await ctx.db.query.member({ where: { auth0id } }, info) + const authId = memberToken.sub + let member = await ctx.db.query.member({ where: { authId } }, info) if (!member) { try { @@ -124,7 +148,6 @@ const resolvers = { } catch (error) { throw new Error(error.message) } - } } return member }, @@ -133,15 +156,12 @@ const resolvers = { data: { name: name, slug: slug, - owner: {connect:{auth0id: owner}}, - members: {create: {role: 'OWNER', member: {connect: {auth0id: owner}}}} + owner: owner } }, info) - .catch((res) => { - console.log('createTeam error: ', res) - const errors = res.graphQLErrors.map((error) => { - return error.message - }) + .catch((err) => { + console.log('createTeam error: ', err) + return err }) }, async deleteTeam(parent, { id }, ctx, info) { @@ -176,25 +196,30 @@ const server = new GraphQLServer({ context: req => ({ ...req, db - }) + }), }) -server.express.post( +server.express.use( server.options.endpoint, checkJwt, (err, req, res, next) => { + console.log('checkJwt: ', err, req.user) if (err) return res.status(401).send(err.message) next() } ) -server.express.post(server.options.endpoint, (req, res, done) => +server.express.post(server.options.endpoint, (err, req, res, done) => { + console.log('getMember: ', err, req.user) getMember(req, res, done, db) -) +}) const whitelist = [ - 'http://localhost:1337', - 'http://0.0.0.0:5000' + 'http://localhost:3000', + 'http://localhost:3001', + 'http://localhost:3002', + 'http://localhost:4000', + 'http://localhost:4002' ] const corsOptionsDelegate = (req, callback) => { var corsOptions @@ -207,12 +232,13 @@ const corsOptionsDelegate = (req, callback) => { } const options = { + port: 4001, cors: corsOptionsDelegate, endpoint: '/graphql', subscriptions: '/graphql', playground: '/playground' } -server.start(options, () => console.log(`Server is running on http://localhost:4000${server.options.endpoint}`)) +server.start(options, () => console.log(`Server is running on http://localhost:4001${server.options.endpoint}`)) -module.exports= { createPrismaMember: createPrismaMember } +module.exports= { createMember } diff --git a/api/src/schema.graphqls b/api/src/schema.graphql similarity index 69% rename from api/src/schema.graphqls rename to api/src/schema.graphql index b61df8546..82bae531d 100644 --- a/api/src/schema.graphqls +++ b/api/src/schema.graphql @@ -12,24 +12,37 @@ type Query { teamById(teamId: String!): Team teamByOwner(ownerId: String!): TeamConnection owner: Member @isAuthenticated - member(auth0id: String!): Member @isAuthenticated + currentMember: Member @isAuthenticated + member(authId: String!): Member @isAuthenticated } type Mutation { authenticate(idToken: String!): Member createTeam(name: String!, slug: String, owner: String): Team @isAuthenticated deleteTeam(id: ID!): Team @isAuthenticated @isOwner(type: "Team") - updateProfile(data: MemberProfileInput): Member @isAuthenticated } input MemberProfileInput { - auth0id: String! - nickname: String! - anonymous: Boolean - visible: Boolean - avatar: String - email: String - repo: String - bio: String - status: String + authId: String! + alias: String! +} + +fragment MemberInfo on Member { + id + authId + alias + isActive + profile { + ...MemberProfileInfo + } +} + +fragment MemberProfileInfo on MemberProfile { + firstName + lastName + email + avatar + role { + name + } } diff --git a/client/src/views/index.js b/client/src/views/index.js index a1e5c1f8a..6759b33df 100644 --- a/client/src/views/index.js +++ b/client/src/views/index.js @@ -3,7 +3,8 @@ import Footer from './footer' import Callback from './callback' import Home from './home' import Dashboard from './dashboard' +import Teams from './teams' import { theme, globalStyles } from './theme' -export { NavBar, Footer, Callback, Home, Dashboard, theme, globalStyles } +export { NavBar, Footer, Callback, Home, Dashboard, Teams, theme, globalStyles } diff --git a/client/src/views/teams/index.js b/client/src/views/teams/index.js new file mode 100644 index 000000000..69dbd99aa --- /dev/null +++ b/client/src/views/teams/index.js @@ -0,0 +1,53 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import CssBaseline from '@material-ui/core/CssBaseline' +import Typography from '@material-ui/core/Typography' +import { withStyles } from '@material-ui/core/styles' + +const styles = theme => ({ + '@global': { + body: { + backgroundColor: theme.palette.common.white + } + }, + layout: { + width: 'auto', + marginLeft: theme.spacing.unit * 3, + marginRight: theme.spacing.unit * 3, + [theme.breakpoints.up(900 + theme.spacing.unit * 3 * 2)]: { + width: 900, + marginLeft: 'auto', + marginRight: 'auto' + } + }, + heroContent: { + maxWidth: 600, + margin: '0 auto', + padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px` + } +}) + +const Home = ({ classes }) => ( + + +
+
+ + Teams + +
+
+
+) + +Home.propTypes = { + classes: PropTypes.object.isRequired +} + +export default withStyles(styles)(Home) diff --git a/docs/CodeStyle.md b/docs/CodeStyle.md new file mode 100644 index 000000000..483afda50 --- /dev/null +++ b/docs/CodeStyle.md @@ -0,0 +1,5 @@ +# Code Styling and Formatting + +``` +npm install --save-dev eslint-config-standard eslint-config-standard-react eslint-plugin-standard eslint-plugin-promise eslint-plugin-import eslint-plugin-node eslint-plugin-react +``` From dde914c43af7cfca75e6aa99640d9a94d976ee46 Mon Sep 17 00:00:00 2001 From: Barry Low Date: Wed, 12 Sep 2018 22:36:33 -0700 Subject: [PATCH 02/16] Client: break apart dashboard --- client/src/App.js | 6 +- .../src/graphql/teams/CreateTeamMutation.js | 2 +- client/src/views/dashboard/ManageTeams.js | 30 +++ client/src/views/dashboard/Overview.js | 73 +++++++ client/src/views/dashboard/TeamMembers.js | 30 +++ .../views/dashboard/components/CreateTeam.js | 16 +- .../views/dashboard/components/DashEditor.js | 50 +++++ .../views/dashboard/components/DashTeam.js | 22 ++ .../dashboard/components/DashTeamItem.js | 72 +++++++ client/src/views/dashboard/index.js | 164 ++------------ client/src/views/dashboard/members.js | 111 ---------- client/src/views/dashboard/settings.js | 202 +----------------- client/src/views/dashboard/teams.js | 111 ---------- 13 files changed, 313 insertions(+), 576 deletions(-) create mode 100644 client/src/views/dashboard/ManageTeams.js create mode 100644 client/src/views/dashboard/Overview.js create mode 100644 client/src/views/dashboard/TeamMembers.js create mode 100644 client/src/views/dashboard/components/DashEditor.js create mode 100644 client/src/views/dashboard/components/DashTeam.js create mode 100644 client/src/views/dashboard/components/DashTeamItem.js delete mode 100644 client/src/views/dashboard/members.js delete mode 100644 client/src/views/dashboard/teams.js diff --git a/client/src/App.js b/client/src/App.js index 5dcdda261..60dddf69d 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -148,7 +148,11 @@ class App extends Component { - + { diff --git a/client/src/graphql/teams/CreateTeamMutation.js b/client/src/graphql/teams/CreateTeamMutation.js index 752546daa..25858f6ed 100644 --- a/client/src/graphql/teams/CreateTeamMutation.js +++ b/client/src/graphql/teams/CreateTeamMutation.js @@ -8,7 +8,7 @@ export const CreateTeamMutation = gql` name slug owner - members{ + members { role member { authId diff --git a/client/src/views/dashboard/ManageTeams.js b/client/src/views/dashboard/ManageTeams.js new file mode 100644 index 000000000..7c284e75e --- /dev/null +++ b/client/src/views/dashboard/ManageTeams.js @@ -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 { TeamTable } from './components/TeamTable' + +const styles = theme => ({ + tableContainer: { + height: 320 + } +}) + +const ManageTeams = ({ classes }) => ( +
+ + Teams + +
+ +
+
+) + +ManageTeams.propTypes = { + classes: PropTypes.object.isRequired +} + +export default withStyles(styles)(ManageTeams) diff --git a/client/src/views/dashboard/Overview.js b/client/src/views/dashboard/Overview.js new file mode 100644 index 000000000..19f30450f --- /dev/null +++ b/client/src/views/dashboard/Overview.js @@ -0,0 +1,73 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { graphql } from 'react-apollo' + +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 { CreateTeamDialog } from './components/CreateTeam' +import { DashTeam } from './components/DashTeam' +import { DashEditor } from './components/DashEditor' + +import { CreateTeamMutation } from '../../graphql/teams/CreateTeamMutation' + +const styles = theme => ({ + card: { + display: 'flex', + width: '100%' + }, + cardDetails: { + display: 'flex', + flex: 1 + }, + cardContent: { + flex: 1 + }, + cardMedia: { + flex: 1, + width: 160, + height: 160, + justifyContent: 'flex-start' + }, + buttonRight: { + justifyContent: 'flex-end' + } +}) + +export const Overview = ({ classes, createTeamMutation }) => ( + + + + +
+ + + +
+
+
+
+ + +
+) + +Overview.propTypes = { + classes: PropTypes.object.isRequired, + createTeamMutation: PropTypes.object +} + +const OverviewWithMutation = graphql(CreateTeamMutation, { + name: 'createTeamMutation', + options: props => ({ + // Options are computed from `props` here. + }) +})(Overview) + +export default withStyles(styles)(OverviewWithMutation) diff --git a/client/src/views/dashboard/TeamMembers.js b/client/src/views/dashboard/TeamMembers.js new file mode 100644 index 000000000..a22de3714 --- /dev/null +++ b/client/src/views/dashboard/TeamMembers.js @@ -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 { TeamTable } from './components/TeamTable' + +const styles = theme => ({ + tableContainer: { + height: 320 + } +}) + +const TeamMembers = ({ classes }) => ( +
+ + Members + +
+ +
+
+) + +TeamMembers.propTypes = { + classes: PropTypes.object.isRequired +} + +export default withStyles(styles)(TeamMembers) diff --git a/client/src/views/dashboard/components/CreateTeam.js b/client/src/views/dashboard/components/CreateTeam.js index 2d0bda554..98e3aebc6 100644 --- a/client/src/views/dashboard/components/CreateTeam.js +++ b/client/src/views/dashboard/components/CreateTeam.js @@ -52,9 +52,7 @@ export class CreateTeamDialog extends Component { onClick={this.handleClickOpen} > - - Create A Team - + Create A Team Subscribe - - Team Creation - - - Name your team! - + Team Creation + Name your team! b.charAt(a.indexOf(c))) // Replace special characters .replace(/&/g, '-and-') // Replace & with 'and' diff --git a/client/src/views/dashboard/components/DashEditor.js b/client/src/views/dashboard/components/DashEditor.js new file mode 100644 index 000000000..1f6aa4cae --- /dev/null +++ b/client/src/views/dashboard/components/DashEditor.js @@ -0,0 +1,50 @@ +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 Card from '@material-ui/core/Card' +import CardMedia from '@material-ui/core/CardMedia' +import CardActions from '@material-ui/core/CardActions' +import Button from '@material-ui/core/Button' + +import aaweb from '../../assets/AlgonetWebPlatform.jpg' + +const styles = theme => ({ + aawebMedia: { + width: '100%', + height: 320 + } +}) + +export const DashEditor = ({ classes }) => ( + + + Develop + + + + + + + + + + + + + + +) + +DashEditor.propTypes = { + classes: PropTypes.object.isRequired +} + +export default withStyles(styles)(DashEditor) diff --git a/client/src/views/dashboard/components/DashTeam.js b/client/src/views/dashboard/components/DashTeam.js new file mode 100644 index 000000000..e56695511 --- /dev/null +++ b/client/src/views/dashboard/components/DashTeam.js @@ -0,0 +1,22 @@ +import React from 'react' +import { Query } from 'react-apollo' + +import Typography from '@material-ui/core/Typography' +import Grid from '@material-ui/core/Grid' + +import { DashTeamIteam } from './DashTeamIteam' + +export const DashTeam = () => ( + + + + Teams + + + + + + +) + +export default DashTeam diff --git a/client/src/views/dashboard/components/DashTeamItem.js b/client/src/views/dashboard/components/DashTeamItem.js new file mode 100644 index 000000000..cdf585c8f --- /dev/null +++ b/client/src/views/dashboard/components/DashTeamItem.js @@ -0,0 +1,72 @@ +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 Card from '@material-ui/core/Card' +import CardContent from '@material-ui/core/CardContent' +import CardMedia from '@material-ui/core/CardMedia' +import CardActions from '@material-ui/core/CardActions' +import Button from '@material-ui/core/Button' + +const styles = theme => ({ + card: { + display: 'flex', + width: '100%' + }, + cardDetails: { + display: 'flex', + flex: 1 + }, + cardContent: { + flex: 1 + }, + cardMedia: { + flex: 1, + width: 160, + height: 160, + justifyContent: 'flex-start' + }, + buttonRight: { + justifyContent: 'flex-end' + } +}) + +export const DashTeamItem = ({ classes }) => ( + + +
+ + + Goodester + + 09.15.2018 + + + Members:6 + + + Now recruiting! + + + + + +
+
+
+) + +DashTeamItem.propTypes = { + classes: PropTypes.object.isRequired +} + +export default withStyles(styles)(DashTeamItem) diff --git a/client/src/views/dashboard/index.js b/client/src/views/dashboard/index.js index 6392347ed..3d39c1057 100644 --- a/client/src/views/dashboard/index.js +++ b/client/src/views/dashboard/index.js @@ -1,25 +1,18 @@ import React from 'react' import PropTypes from 'prop-types' -import { graphql } from 'react-apollo' +import { Route, Switch } from 'react-router-dom' -import Typography from '@material-ui/core/Typography' import { withStyles } from '@material-ui/core/styles' import Drawer from '@material-ui/core/Drawer' import List from '@material-ui/core/List' import Divider from '@material-ui/core/Divider' -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 CardActions from '@material-ui/core/CardActions' -import Button from '@material-ui/core/Button' import { MainDrawerItems, SecondaryDrawerItems } from './components/DrawerLinks' -import { CreateTeamDialog } from './components/CreateTeam' -import { CreateTeamMutation } from '../../graphql/teams/CreateTeamMutation' - -import aaweb from '../../assets/AlgonetWebPlatform.jpg' +import { Overview } from 'Overview' +import { ManageTeams } from 'ManageTeams' +import { TeamMembers } from 'TeamMembers' +import { Settings } from 'Settings' const drawerWidth = 240 @@ -49,37 +42,7 @@ const styles = theme => ({ overflow: 'auto', width: `calc(90% - ${drawerWidth}px)` }, - appBarSpacer: theme.mixins.toolbar, - tableContainer: { - height: 320 - }, - card: { - display: 'flex', - width: '100%' - }, - cardDetails: { - display: 'flex', - flex: 1 - }, - cardContent: { - flex: 1 - }, - cardMedia: { - flex: 1, - width: 160, - height: 160, - justifyContent: 'flex-start' - }, - aawebMedia: { - width: '100%', - height: 320 - }, - buttonRight: { - justifyContent: 'flex-end' - }, - extendedIcon: { - marginRight: theme.spacing.unit - } + appBarSpacer: theme.mixins.toolbar }) const Dashboard = ({ classes, createTeamMutation, ...props }) => ( @@ -97,109 +60,12 @@ const Dashboard = ({ classes, createTeamMutation, ...props }) => (
- - - - Teams - - - - -
- - - -
-
-
- - -
- - - Goodester - - 09.15.2018 - - - Members:6 - - - Now recruiting! - - - - - -
-
-
- - -
- - - Goodester - - 09.15.2018 - - - Members:6 - - - Now recruiting! - - - - - -
-
-
-
-
- - - Develop - - - - - - - - - - - - - - -
+ + + + + +
) @@ -209,8 +75,4 @@ Dashboard.propTypes = { createTeamMutation: PropTypes.function } -const CreateTeamDialogWithMutation = graphql(CreateTeamMutation, { - name: 'createTeamMutation' // name of the injected prop: this.props.createTeamMutation... -})(Dashboard) - -export default withStyles(styles)(CreateTeamDialogWithMutation) +export default withStyles(styles)(Dashboard) diff --git a/client/src/views/dashboard/members.js b/client/src/views/dashboard/members.js deleted file mode 100644 index da5524ed0..000000000 --- a/client/src/views/dashboard/members.js +++ /dev/null @@ -1,111 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import { graphql } from 'react-apollo' - -import Typography from '@material-ui/core/Typography' -import { withStyles } from '@material-ui/core/styles' -import Drawer from '@material-ui/core/Drawer' -import List from '@material-ui/core/List' -import Divider from '@material-ui/core/Divider' - -import { MainDrawerItems, SecondaryDrawerItems } from './components/DrawerLinks' -import { TeamTable } from './components/TeamTable' - -import { CreateTeamMutation } from '../../graphql/teams/CreateTeamMutation' - -const drawerWidth = 240 - -const styles = theme => ({ - root: { - display: 'flex' - }, - '@global': { - body: { - backgroundColor: theme.palette.common.white - } - }, - appBar: { - zIndex: theme.zIndex.drawer + 1 - }, - drawerPaper: { - position: 'relative', - width: drawerWidth, - whiteSpace: 'nowrap', - zIndex: 1000 - }, - content: { - flexGrow: 1, - backgroundColor: theme.palette.background.default, - padding: theme.spacing.unit * 3, - height: '100vh', - overflow: 'auto', - width: `calc(90% - ${drawerWidth}px)` - }, - appBarSpacer: theme.mixins.toolbar, - tableContainer: { - height: 320 - }, - card: { - display: 'flex', - width: '100%' - }, - cardDetails: { - display: 'flex', - flex: 1 - }, - cardContent: { - flex: 1 - }, - cardMedia: { - flex: 1, - width: 160, - height: 160, - justifyContent: 'flex-start' - }, - aawebMedia: { - width: '100%', - height: 320 - }, - buttonRight: { - justifyContent: 'flex-end' - }, - extendedIcon: { - marginRight: theme.spacing.unit - } -}) - -const Dashboard = ({ classes, createTeamMutation, ...props }) => ( -
- -
- {MainDrawerItems} - - {SecondaryDrawerItems} - -
-
- - Members - -
- -
-
-
-) - -Dashboard.propTypes = { - classes: PropTypes.object.isRequired, - createTeamMutation: PropTypes.function -} - -const CreateTeamDialogWithMutation = graphql(CreateTeamMutation, { - name: 'createTeamMutation' // name of the injected prop: this.props.createTeamMutation... -})(Dashboard) - -export default withStyles(styles)(CreateTeamDialogWithMutation) diff --git a/client/src/views/dashboard/settings.js b/client/src/views/dashboard/settings.js index 0fac8c47e..3ae32bfcc 100644 --- a/client/src/views/dashboard/settings.js +++ b/client/src/views/dashboard/settings.js @@ -1,210 +1,30 @@ import React from 'react' import PropTypes from 'prop-types' -import { graphql } from 'react-apollo' import Typography from '@material-ui/core/Typography' import { withStyles } from '@material-ui/core/styles' -import Drawer from '@material-ui/core/Drawer' -import List from '@material-ui/core/List' -import Divider from '@material-ui/core/Divider' -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 CardActions from '@material-ui/core/CardActions' -import Button from '@material-ui/core/Button' -import { MainDrawerItems, SecondaryDrawerItems } from './components/DrawerLinks' import { TeamTable } from './components/TeamTable' -import { CreateTeamDialog } from './components/CreateTeam' - -import { CreateTeamMutation } from '../../graphql/teams/CreateTeamMutation' - -const drawerWidth = 240 const styles = theme => ({ - root: { - display: 'flex' - }, - '@global': { - body: { - backgroundColor: theme.palette.common.white - } - }, - appBar: { - zIndex: theme.zIndex.drawer + 1 - }, - drawerPaper: { - position: 'relative', - width: drawerWidth, - whiteSpace: 'nowrap', - zIndex: 1000 - }, - content: { - flexGrow: 1, - backgroundColor: theme.palette.background.default, - padding: theme.spacing.unit * 3, - height: '100vh', - overflow: 'auto', - width: `calc(90% - ${drawerWidth}px)` - }, - appBarSpacer: theme.mixins.toolbar, tableContainer: { height: 320 - }, - card: { - display: 'flex', - width: '100%' - }, - cardDetails: { - display: 'flex', - flex: 1 - }, - cardContent: { - flex: 1 - }, - cardMedia: { - flex: 1, - width: 160, - height: 160, - justifyContent: 'flex-start' - }, - aawebMedia: { - width: '100%', - height: 320 - }, - buttonRight: { - justifyContent: 'flex-end' - }, - extendedIcon: { - marginRight: theme.spacing.unit } }) -const Dashboard = ({ classes, createTeamMutation, ...props }) => ( -
- -
- {MainDrawerItems} - - {SecondaryDrawerItems} - -
-
- - - - Settings - - - - -
- - - -
-
-
- - -
- - - Goodester - - 09.15.2018 - - - Members:6 - - - Now recruiting! - - - - - -
-
-
- - -
- - - Goodester - - 09.15.2018 - - - Members:6 - - - Now recruiting! - - - - - -
-
-
-
-
- - - Notifications - - - - - - - - - - - - - -
-
+const Settings = ({ classes }) => ( +
+ + Settings + +
+ +
) -Dashboard.propTypes = { - classes: PropTypes.object.isRequired, - createTeamMutation: PropTypes.function +Settings.propTypes = { + classes: PropTypes.object.isRequired } -const CreateTeamDialogWithMutation = graphql(CreateTeamMutation, { - name: 'createTeamMutation' // name of the injected prop: this.props.createTeamMutation... -})(Dashboard) - -export default withStyles(styles)(CreateTeamDialogWithMutation) +export default withStyles(styles)(Settings) diff --git a/client/src/views/dashboard/teams.js b/client/src/views/dashboard/teams.js deleted file mode 100644 index 9d223e372..000000000 --- a/client/src/views/dashboard/teams.js +++ /dev/null @@ -1,111 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import { graphql } from 'react-apollo' - -import Typography from '@material-ui/core/Typography' -import { withStyles } from '@material-ui/core/styles' -import Drawer from '@material-ui/core/Drawer' -import List from '@material-ui/core/List' -import Divider from '@material-ui/core/Divider' - -import { MainDrawerItems, SecondaryDrawerItems } from './components/DrawerLinks' -import { TeamTable } from './components/TeamTable' - -import { CreateTeamMutation } from '../../graphql/teams/CreateTeamMutation' - -const drawerWidth = 240 - -const styles = theme => ({ - root: { - display: 'flex' - }, - '@global': { - body: { - backgroundColor: theme.palette.common.white - } - }, - appBar: { - zIndex: theme.zIndex.drawer + 1 - }, - drawerPaper: { - position: 'relative', - width: drawerWidth, - whiteSpace: 'nowrap', - zIndex: 1000 - }, - content: { - flexGrow: 1, - backgroundColor: theme.palette.background.default, - padding: theme.spacing.unit * 3, - height: '100vh', - overflow: 'auto', - width: `calc(90% - ${drawerWidth}px)` - }, - appBarSpacer: theme.mixins.toolbar, - tableContainer: { - height: 320 - }, - card: { - display: 'flex', - width: '100%' - }, - cardDetails: { - display: 'flex', - flex: 1 - }, - cardContent: { - flex: 1 - }, - cardMedia: { - flex: 1, - width: 160, - height: 160, - justifyContent: 'flex-start' - }, - aawebMedia: { - width: '100%', - height: 320 - }, - buttonRight: { - justifyContent: 'flex-end' - }, - extendedIcon: { - marginRight: theme.spacing.unit - } -}) - -const Dashboard = ({ classes, createTeamMutation, ...props }) => ( -
- -
- {MainDrawerItems} - - {SecondaryDrawerItems} - -
-
- - Teams - -
- -
-
-
-) - -Dashboard.propTypes = { - classes: PropTypes.object.isRequired, - createTeamMutation: PropTypes.function -} - -const CreateTeamDialogWithMutation = graphql(CreateTeamMutation, { - name: 'createTeamMutation' // name of the injected prop: this.props.createTeamMutation... -})(Dashboard) - -export default withStyles(styles)(CreateTeamDialogWithMutation) From 14425dc233a7a4a02e906a1bb2754b5f116b9b9f Mon Sep 17 00:00:00 2001 From: Barry Low Date: Wed, 12 Sep 2018 22:43:12 -0700 Subject: [PATCH 03/16] Client: fix dashboard paths --- client/src/views/dashboard/ManageTeams.js | 2 +- client/src/views/dashboard/TeamMembers.js | 2 +- client/src/views/dashboard/components/DashEditor.js | 2 +- client/src/views/dashboard/components/DashTeam.js | 2 +- client/src/views/dashboard/index.js | 8 ++++---- client/src/views/dashboard/settings.js | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/client/src/views/dashboard/ManageTeams.js b/client/src/views/dashboard/ManageTeams.js index 7c284e75e..432007a95 100644 --- a/client/src/views/dashboard/ManageTeams.js +++ b/client/src/views/dashboard/ManageTeams.js @@ -12,7 +12,7 @@ const styles = theme => ({ } }) -const ManageTeams = ({ classes }) => ( +export const ManageTeams = ({ classes }) => (
Teams diff --git a/client/src/views/dashboard/TeamMembers.js b/client/src/views/dashboard/TeamMembers.js index a22de3714..ab74d6f31 100644 --- a/client/src/views/dashboard/TeamMembers.js +++ b/client/src/views/dashboard/TeamMembers.js @@ -12,7 +12,7 @@ const styles = theme => ({ } }) -const TeamMembers = ({ classes }) => ( +export const TeamMembers = ({ classes }) => (
Members diff --git a/client/src/views/dashboard/components/DashEditor.js b/client/src/views/dashboard/components/DashEditor.js index 1f6aa4cae..095f22300 100644 --- a/client/src/views/dashboard/components/DashEditor.js +++ b/client/src/views/dashboard/components/DashEditor.js @@ -10,7 +10,7 @@ import CardMedia from '@material-ui/core/CardMedia' import CardActions from '@material-ui/core/CardActions' import Button from '@material-ui/core/Button' -import aaweb from '../../assets/AlgonetWebPlatform.jpg' +import aaweb from '../../../assets/AlgonetWebPlatform.jpg' const styles = theme => ({ aawebMedia: { diff --git a/client/src/views/dashboard/components/DashTeam.js b/client/src/views/dashboard/components/DashTeam.js index e56695511..e5be5398b 100644 --- a/client/src/views/dashboard/components/DashTeam.js +++ b/client/src/views/dashboard/components/DashTeam.js @@ -4,7 +4,7 @@ import { Query } from 'react-apollo' import Typography from '@material-ui/core/Typography' import Grid from '@material-ui/core/Grid' -import { DashTeamIteam } from './DashTeamIteam' +import { DashTeamIteam } from './DashTeamItem' export const DashTeam = () => ( diff --git a/client/src/views/dashboard/index.js b/client/src/views/dashboard/index.js index 3d39c1057..b6331118d 100644 --- a/client/src/views/dashboard/index.js +++ b/client/src/views/dashboard/index.js @@ -9,10 +9,10 @@ import Divider from '@material-ui/core/Divider' import { MainDrawerItems, SecondaryDrawerItems } from './components/DrawerLinks' -import { Overview } from 'Overview' -import { ManageTeams } from 'ManageTeams' -import { TeamMembers } from 'TeamMembers' -import { Settings } from 'Settings' +import { Overview } from './Overview' +import { ManageTeams } from './ManageTeams' +import { TeamMembers } from './TeamMembers' +import { Settings } from './Settings' const drawerWidth = 240 diff --git a/client/src/views/dashboard/settings.js b/client/src/views/dashboard/settings.js index 3ae32bfcc..a9ee58b58 100644 --- a/client/src/views/dashboard/settings.js +++ b/client/src/views/dashboard/settings.js @@ -12,7 +12,7 @@ const styles = theme => ({ } }) -const Settings = ({ classes }) => ( +export const Settings = ({ classes }) => (
Settings From 1637abbc885ef07ed49420348a4f557bca402b4a Mon Sep 17 00:00:00 2001 From: Barry Low Date: Thu, 13 Sep 2018 16:33:47 -0700 Subject: [PATCH 04/16] Client: update named imports to default imports --- api/src/index.js | 25 +-- api/src/schema.graphql | 2 +- client/src/App.js | 2 +- client/src/auth/index.js | 2 +- .../src/graphql/teams/CreateTeamMutation.js | 4 +- client/src/graphql/teams/GetTeamQuery.js | 40 ---- .../src/graphql/teams/GetTeamsByOwnerQuery.js | 38 ++++ client/src/utils/js-helpers.js | 4 + client/src/views/dashboard/ManageTeams.js | 4 +- client/src/views/dashboard/Overview.js | 72 +++---- client/src/views/dashboard/TeamMembers.js | 2 +- .../views/dashboard/components/CreateTeam.js | 198 +++++++----------- .../dashboard/components/CreateTeamForm.js | 131 ++++++++++++ .../views/dashboard/components/DashEditor.js | 10 +- .../views/dashboard/components/DashTeam.js | 99 ++++++++- .../views/dashboard/components/DrawerLinks.js | 6 +- client/src/views/dashboard/index.js | 29 ++- 17 files changed, 419 insertions(+), 249 deletions(-) delete mode 100644 client/src/graphql/teams/GetTeamQuery.js create mode 100644 client/src/graphql/teams/GetTeamsByOwnerQuery.js create mode 100644 client/src/views/dashboard/components/CreateTeamForm.js diff --git a/api/src/index.js b/api/src/index.js index be92331cd..d81c1e1eb 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -83,7 +83,7 @@ const resolvers = { async teamByName(parent, { name }, ctx, info) { return ctx.db.query.team({ where: { name: name } }, `{ name }`) }, - async teamByOwner(parent, { ownerId }, ctx, info) { + async teamsByOwner(parent, { ownerId }, ctx, info) { return ctx.db.query.teamsConnection({where: { owner: { authId: ownerId }}}, `{ edges { @@ -91,27 +91,24 @@ const resolvers = { id name slug + owner + status { + status + reason + createdAt + } + createdAt profile { avatar description motto - } - owner { - authId - nickname - visible - profile { - avatar - } + updatedAt } members { role member { - nickname - visible - profile { - avatar - } + alias + authId } } } diff --git a/api/src/schema.graphql b/api/src/schema.graphql index 82bae531d..f63570229 100644 --- a/api/src/schema.graphql +++ b/api/src/schema.graphql @@ -10,7 +10,7 @@ type Query { teamDetails: [Team!]! @isAuthenticated teamByName(name: String!): Team teamById(teamId: String!): Team - teamByOwner(ownerId: String!): TeamConnection + teamsByOwner(ownerId: String!): TeamConnection owner: Member @isAuthenticated currentMember: Member @isAuthenticated member(authId: String!): Member @isAuthenticated diff --git a/client/src/App.js b/client/src/App.js index 60dddf69d..adf708aa3 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -151,7 +151,7 @@ class App extends Component { } /> (a || {})[b], object) !== undefined } diff --git a/client/src/views/dashboard/ManageTeams.js b/client/src/views/dashboard/ManageTeams.js index 432007a95..ecf65c9db 100644 --- a/client/src/views/dashboard/ManageTeams.js +++ b/client/src/views/dashboard/ManageTeams.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types' import Typography from '@material-ui/core/Typography' import { withStyles } from '@material-ui/core/styles' -import { TeamTable } from './components/TeamTable' +import TeamTable from './components/TeamTable' const styles = theme => ({ tableContainer: { @@ -12,7 +12,7 @@ const styles = theme => ({ } }) -export const ManageTeams = ({ classes }) => ( +const ManageTeams = ({ classes }) => (
Teams diff --git a/client/src/views/dashboard/Overview.js b/client/src/views/dashboard/Overview.js index 19f30450f..19d8a2bf9 100644 --- a/client/src/views/dashboard/Overview.js +++ b/client/src/views/dashboard/Overview.js @@ -1,20 +1,19 @@ -import React from 'react' +import React, { Component } from 'react' import PropTypes from 'prop-types' -import { graphql } from 'react-apollo' - 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 { CreateTeamDialog } from './components/CreateTeam' -import { DashTeam } from './components/DashTeam' -import { DashEditor } from './components/DashEditor' - -import { CreateTeamMutation } from '../../graphql/teams/CreateTeamMutation' +import CreateTeam from './components/CreateTeam' +import DashTeam from './components/DashTeam' +import DashEditor from './components/DashEditor' const styles = theme => ({ + root: { + display: 'flex' + }, card: { display: 'flex', width: '100%' @@ -34,40 +33,37 @@ const styles = theme => ({ }, buttonRight: { justifyContent: 'flex-end' + }, + aawebMedia: { + width: '100%', + height: 320 } }) -export const Overview = ({ classes, createTeamMutation }) => ( - - - - -
- - - -
-
+export class Overview extends Component { + render () { + const { classes } = this.props + return ( + + + + +
+ + + +
+
+
+
+ +
-
- - -
-) - + ) + } +} Overview.propTypes = { - classes: PropTypes.object.isRequired, - createTeamMutation: PropTypes.object + classes: PropTypes.object.isRequired } -const OverviewWithMutation = graphql(CreateTeamMutation, { - name: 'createTeamMutation', - options: props => ({ - // Options are computed from `props` here. - }) -})(Overview) - -export default withStyles(styles)(OverviewWithMutation) +export default withStyles(styles)(Overview) diff --git a/client/src/views/dashboard/TeamMembers.js b/client/src/views/dashboard/TeamMembers.js index ab74d6f31..a22de3714 100644 --- a/client/src/views/dashboard/TeamMembers.js +++ b/client/src/views/dashboard/TeamMembers.js @@ -12,7 +12,7 @@ const styles = theme => ({ } }) -export const TeamMembers = ({ classes }) => ( +const TeamMembers = ({ classes }) => (
Members diff --git a/client/src/views/dashboard/components/CreateTeam.js b/client/src/views/dashboard/components/CreateTeam.js index 98e3aebc6..b01184b7d 100644 --- a/client/src/views/dashboard/components/CreateTeam.js +++ b/client/src/views/dashboard/components/CreateTeam.js @@ -1,131 +1,87 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import { withRouter } from 'react-router-dom' -import Button from '@material-ui/core/Button' -import AddIcon from '@material-ui/icons/Add' -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 React from 'react' +import { Mutation } from 'react-apollo' + import Typography from '@material-ui/core/Typography' import { getItem } from '../../../utils/local-storage' -export class CreateTeamDialog extends Component { - constructor (props) { - super(props) +import CREATE_TEAM from '../../../graphql/teams/CreateTeamMutation' +import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery' - this.handleClickOpen = this.handleClickOpen.bind(this) - this.handleClose = this.handleClose.bind(this) - this.handlePost = this.handlePost.bind(this) - this.slugify = this.slugify.bind(this) - this.handleChange = this.handleChange.bind(this) +const CreateTeam = () => { + let input - this.state = { - open: false, - name: '' - } - } - - handleClickOpen () { - this.setState({ open: true }) - } - - handleClose () { - this.setState({ open: false }) - } - - handleChange (e) { - this.setState({ name: e.target.value }) - } - - render () { - console.log(this.props) - return ( -
- - - Subscribe - - Team Creation - Name your team! - - - - - - - -
- ) - } - - 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 - } - - async handlePost (e) { - e.preventDefault() - const { name } = this.state - const slug = this.slugify(name) - const currentUser = await getItem('user') - let authId = JSON.parse(currentUser) - authId = authId.sub - console.log('createPage cu:', JSON.parse(currentUser)) - await this.props.createTeamMutation({ - variables: { - name, - slug, - owner: authId - } - }) - this.setState({ open: false }) - } + return ( + { + const { teamsByOwner } = cache.readQuery({ query: GET_TEAMS_BY_OWNER }) + cache.writeQuery({ + query: GET_TEAMS_BY_OWNER, + data: { teamsByOwner: teamsByOwner.concat([createTeam]) } + }) + }} + > + {(createTeam, { loading, error, data }) => { + let errors + let loader + if (loading) { + loader = (Submitting team...) + } + if (error) { + errors = error.graphQLErrors.map(({ message }, i) => ( + {message} + )) + } + return ( +
+
{ + handleSubmit(e, createTeam, input) + }} + > + { + input = node + }} + /> + +
+ {loader} + {errors} +
+ ) + }} +
+ ) } -CreateTeamDialog.propTypes = { - classes: PropTypes.object.isRequired, - createTeamMutation: PropTypes.function +const handleSubmit = async (e, createTeam, input) => { + e.preventDefault() + const currentUser = await getItem('user') + let authId = JSON.parse(currentUser) + authId = authId.sub + const name = input.value + const slug = slugify(name) + await createTeam({ variables: { name, slug, owner: authId } }) + input.value = '' } -export default withRouter(CreateTeamDialog) +const 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 +} + +export default CreateTeam diff --git a/client/src/views/dashboard/components/CreateTeamForm.js b/client/src/views/dashboard/components/CreateTeamForm.js new file mode 100644 index 000000000..98e3aebc6 --- /dev/null +++ b/client/src/views/dashboard/components/CreateTeamForm.js @@ -0,0 +1,131 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import { withRouter } from 'react-router-dom' +import Button from '@material-ui/core/Button' +import AddIcon from '@material-ui/icons/Add' +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 { getItem } from '../../../utils/local-storage' + +export class CreateTeamDialog extends Component { + constructor (props) { + super(props) + + this.handleClickOpen = this.handleClickOpen.bind(this) + this.handleClose = this.handleClose.bind(this) + this.handlePost = this.handlePost.bind(this) + this.slugify = this.slugify.bind(this) + this.handleChange = this.handleChange.bind(this) + + this.state = { + open: false, + name: '' + } + } + + handleClickOpen () { + this.setState({ open: true }) + } + + handleClose () { + this.setState({ open: false }) + } + + handleChange (e) { + this.setState({ name: e.target.value }) + } + + render () { + console.log(this.props) + return ( +
+ + + Subscribe + + Team Creation + Name your team! + + + + + + + +
+ ) + } + + 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 + } + + async handlePost (e) { + e.preventDefault() + const { name } = this.state + const slug = this.slugify(name) + const currentUser = await getItem('user') + let authId = JSON.parse(currentUser) + authId = authId.sub + console.log('createPage cu:', JSON.parse(currentUser)) + await this.props.createTeamMutation({ + variables: { + name, + slug, + owner: authId + } + }) + this.setState({ open: false }) + } +} + +CreateTeamDialog.propTypes = { + classes: PropTypes.object.isRequired, + createTeamMutation: PropTypes.function +} + +export default withRouter(CreateTeamDialog) diff --git a/client/src/views/dashboard/components/DashEditor.js b/client/src/views/dashboard/components/DashEditor.js index 095f22300..246a921f0 100644 --- a/client/src/views/dashboard/components/DashEditor.js +++ b/client/src/views/dashboard/components/DashEditor.js @@ -2,7 +2,6 @@ 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 Card from '@material-ui/core/Card' @@ -12,13 +11,6 @@ import Button from '@material-ui/core/Button' import aaweb from '../../../assets/AlgonetWebPlatform.jpg' -const styles = theme => ({ - aawebMedia: { - width: '100%', - height: 320 - } -}) - export const DashEditor = ({ classes }) => ( @@ -47,4 +39,4 @@ DashEditor.propTypes = { classes: PropTypes.object.isRequired } -export default withStyles(styles)(DashEditor) +export default DashEditor diff --git a/client/src/views/dashboard/components/DashTeam.js b/client/src/views/dashboard/components/DashTeam.js index e5be5398b..f46bb6e30 100644 --- a/client/src/views/dashboard/components/DashTeam.js +++ b/client/src/views/dashboard/components/DashTeam.js @@ -1,22 +1,105 @@ import React from 'react' +import PropTypes from 'prop-types' import { Query } from 'react-apollo' +import { withStateHandlers, lifecycle, compose } from 'recompose' import Typography from '@material-ui/core/Typography' import Grid from '@material-ui/core/Grid' -import { DashTeamIteam } from './DashTeamItem' +import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery' -export const DashTeam = () => ( - +import DashTeamItem from './DashTeamItem' + +import { isDefined, isString } from '../../../utils/js-helpers' +import { getItem } from '../../../utils/local-storage' + +export const DashTeam = ({ user = null }) => { + console.log('DashTeam 1: ', user) + let owner + let loader + let authId = null + if (user !== null && isString(user)) { + owner = JSON.parse(user) + if (isDefined(owner.sub)) authId = owner.sub + } else { + loader = (Loading...) + } + + console.log('DashTeam 2: ', owner, authId) + if (authId === null) { + return ( + + + Teams + + Loading... + + ) + } + return ( Teams - - - + + {({ loading, error, data }) => { + console.log('GET_TEAMS_BY_OWNER: ', loading, error, data) + let errors + let queryLoader + if (error) { + errors = error.graphQLErrors.map(({ message }, i) => ( + {message} + )) + } + if (!loading) { + return ( + + {!loading && data.teamsByOwner.edges.map(team => ( + + ))} + {queryLoader} + {errors} + {loader} + + ) + } else { + return ( + + + Loading... + + {queryLoader} + {errors} + + ) + } + }} + - + ) +} + +DashTeam.propTypes = { + user: PropTypes.any +} + +const getUserOnMount = lifecycle({ + componentDidMount () { + getItem('user').then(user => { + this.setState({ user }) + }) // Set user to state + } +}) + +const mapStateToProps = withStateHandlers( + () => ({ user: null }), { + user: ({ user }) => () => ({ user }) + } ) -export default DashTeam +const DashTeamAuthId = compose( + mapStateToProps, + getUserOnMount +)(DashTeam) + +export default DashTeamAuthId diff --git a/client/src/views/dashboard/components/DrawerLinks.js b/client/src/views/dashboard/components/DrawerLinks.js index b2a178697..66d9e7d51 100644 --- a/client/src/views/dashboard/components/DrawerLinks.js +++ b/client/src/views/dashboard/components/DrawerLinks.js @@ -13,8 +13,8 @@ import SentimentSatisfiedAltIcon from '@material-ui/icons/SentimentSatisfiedAlt' import AndroidIcon from '@material-ui/icons/Android' const DashboardLink = props => -const TeamsLink = props => -const MembersLink = props => +const TeamsLink = props => +const MembersLink = props => const SettingsLink = props => export const MainDrawerItems = ( @@ -35,7 +35,7 @@ export const MainDrawerItems = ( - + diff --git a/client/src/views/dashboard/index.js b/client/src/views/dashboard/index.js index b6331118d..f62ac733a 100644 --- a/client/src/views/dashboard/index.js +++ b/client/src/views/dashboard/index.js @@ -1,6 +1,7 @@ import React from 'react' import PropTypes from 'prop-types' import { Route, Switch } from 'react-router-dom' +import { lifecycle } from 'recompose' import { withStyles } from '@material-ui/core/styles' import Drawer from '@material-ui/core/Drawer' @@ -9,10 +10,10 @@ import Divider from '@material-ui/core/Divider' import { MainDrawerItems, SecondaryDrawerItems } from './components/DrawerLinks' -import { Overview } from './Overview' -import { ManageTeams } from './ManageTeams' -import { TeamMembers } from './TeamMembers' -import { Settings } from './Settings' +import Overview from './Overview' +import ManageTeams from './ManageTeams' +import TeamMembers from './TeamMembers' +import Settings from './Settings' const drawerWidth = 240 @@ -45,7 +46,7 @@ const styles = theme => ({ appBarSpacer: theme.mixins.toolbar }) -const Dashboard = ({ classes, createTeamMutation, ...props }) => ( +const Dashboard = ({ classes }) => (
(
- + @@ -71,8 +72,18 @@ const Dashboard = ({ classes, createTeamMutation, ...props }) => ( ) Dashboard.propTypes = { - classes: PropTypes.object.isRequired, - createTeamMutation: PropTypes.function + classes: PropTypes.object.isRequired } -export default withStyles(styles)(Dashboard) +const DashboardCheckSession = lifecycle({ + async componentDidMount () { + try { + const authenticated = await this.props.auth.isAuthenticated() + console.log('DashboardCheckSession res: ', authenticated) + } catch (err) { + console.log('DashboardCheckSession err: ', err) + } + } +})(Dashboard) + +export default withStyles(styles)(DashboardCheckSession) From f7c5e9cc70fd3d392f7d2c756b7274c364544abc Mon Sep 17 00:00:00 2001 From: Barry Low Date: Thu, 13 Sep 2018 21:42:02 -0700 Subject: [PATCH 05/16] Client: create DashCreateTeamWrapper --- api/src/index.js | 22 ++++----- client/src/auth/index.js | 32 ++++++------ client/src/graphql/teams/GetAllTeamsQuery.js | 22 ++++----- client/src/graphql/teams/Teams.js | 36 ++++++++++++++ client/src/utils/graphql-errors.js | 13 +++++ client/src/views/dashboard/Overview.js | 15 +----- .../dashboard/components/CreateTeamWrapper.js | 49 +++++++++++++++++++ .../views/dashboard/components/DashTeam.js | 48 +++++++++++------- 8 files changed, 167 insertions(+), 70 deletions(-) create mode 100644 client/src/graphql/teams/Teams.js create mode 100644 client/src/utils/graphql-errors.js create mode 100644 client/src/views/dashboard/components/CreateTeamWrapper.js diff --git a/api/src/index.js b/api/src/index.js index d81c1e1eb..a6598ea9b 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -51,26 +51,24 @@ const resolvers = { id name slug + owner + status { + status + reason + createdAt + } + createdAt profile { avatar description motto - } - owner { - nickname - visible - profile { - avatar - } + updatedAt } members { role member { - nickname - visible - profile { - avatar - } + alias + authId } } } diff --git a/client/src/auth/index.js b/client/src/auth/index.js index 2196c4f38..05ea56a26 100644 --- a/client/src/auth/index.js +++ b/client/src/auth/index.js @@ -102,7 +102,11 @@ class Auth { this.signinOrCreateAccount({ ...data }) this.cb(data) console.log(authResult.idTokenPayload) - setItem('user', JSON.stringify(authResult.idTokenPayload)) + const user = { + authID: authResult.idTokenPayload.sub, + alias: authResult.idTokenPayload.nickname + } + setItem('user', JSON.stringify(user)) if (window.location.href.includes(`callback`)) { // window.location.href = '/dashboard' } @@ -126,11 +130,13 @@ class Auth { }) console.log('signinOrCreateAccount auth: ', await data) - setItem('user', JSON.stringify(data.data.authenticate)) + const user = { + authID: data.data.authenticate.authId, + alias: data.data.authenticate.authId.alias + } + setItem('user', JSON.stringify(user)) if (window.location.href.includes(`callback`)) { window.location.href = '/dashboard' - } else { - window.location.reload() } return data } catch (err) { @@ -157,10 +163,11 @@ class Auth { async isAuthenticated () { // check session and run Auth0 SS0 const getUser = await getItem('user') + const getExpires = await getItem('expires_at') let user = JSON.parse(getUser) - if (validObject(user, 'exp') && new Date().getTime() < user.exp * 1000) { - console.log('handleAuth.user exp: ', user, window.location.href) + if (new Date().getTime() < getExpires * 1000) { + console.log('handleAuth.user exp: ', user, getExpires, window.location.href) return user } @@ -168,7 +175,11 @@ class Auth { const checkSSO = await this.checkSession() .then(result => { console.log('handleAuth.checksessions: ', result) - setItem('user', result.idTokenPayload.sub) + const user = { + authID: result.idTokenPayload.sub, + alias: result.idTokenPayload.nickname + } + setItem('user', JSON.stringify(user)) // user confirmed, log into client this.setSession(result) return result.idTokenPayload @@ -180,13 +191,6 @@ class Auth { } return err }) - if ( - (window.location.href.includes(`manage`) || - window.location.href.includes(`profile`)) && - !user - ) { - window.location.href = '/' - } if (/manage|profile|create|dashboard/.test(window.location.href) && !user) { this.login() diff --git a/client/src/graphql/teams/GetAllTeamsQuery.js b/client/src/graphql/teams/GetAllTeamsQuery.js index 12acb8702..55902f4c8 100644 --- a/client/src/graphql/teams/GetAllTeamsQuery.js +++ b/client/src/graphql/teams/GetAllTeamsQuery.js @@ -9,26 +9,24 @@ export const GetAllTeamsQuery = gql` id name slug + owner + status { + status + reason + createdAt + } + createdAt profile { avatar description motto - } - owner { - nickname - visible - profile { - avatar - } + updatedAt } members { role member { - nickname - visible - profile { - avatar - } + alias + authId } } } diff --git a/client/src/graphql/teams/Teams.js b/client/src/graphql/teams/Teams.js new file mode 100644 index 000000000..23e54fcc3 --- /dev/null +++ b/client/src/graphql/teams/Teams.js @@ -0,0 +1,36 @@ +/* eslint-disable no-unused-vars */ +import gql from 'graphql-tag' + +export const TEAMS_FRAGMENT = gql` + fragment TeamsRespons on teamsConnection { + edges { + node { + id + name + slug + owner + status { + status + reason + createdAt + } + createdAt + profile { + avatar + description + motto + updatedAt + } + members { + role + member { + alias + authId + } + } + } + } + } +` + +export default TEAMS_FRAGMENT diff --git a/client/src/utils/graphql-errors.js b/client/src/utils/graphql-errors.js new file mode 100644 index 000000000..3df684a1d --- /dev/null +++ b/client/src/utils/graphql-errors.js @@ -0,0 +1,13 @@ +const ErrorResponse = { + 'unique constraint': 'Sorry, already taken! Please create a unique ' +} + +export const checkGraphQLError = (error) => { + console.log('checkGraphQLError ', ErrorResponse) + if (error.search(/unique constraint/)) { + const field = error.substring(error.indexOf('=') + 1) + console.log('unique constraint', field.replace(/ +/g, '')) + } +} + +export default checkGraphQLError diff --git a/client/src/views/dashboard/Overview.js b/client/src/views/dashboard/Overview.js index 19d8a2bf9..c79b2eec9 100644 --- a/client/src/views/dashboard/Overview.js +++ b/client/src/views/dashboard/Overview.js @@ -3,10 +3,7 @@ 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 CreateTeam from './components/CreateTeam' import DashTeam from './components/DashTeam' import DashEditor from './components/DashEditor' @@ -45,23 +42,13 @@ export class Overview extends Component { const { classes } = this.props return ( - - - -
- - - -
-
-
-
) } } + Overview.propTypes = { classes: PropTypes.object.isRequired } diff --git a/client/src/views/dashboard/components/CreateTeamWrapper.js b/client/src/views/dashboard/components/CreateTeamWrapper.js new file mode 100644 index 000000000..c4a44b312 --- /dev/null +++ b/client/src/views/dashboard/components/CreateTeamWrapper.js @@ -0,0 +1,49 @@ +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 CreateTeam from './CreateTeam' + +const styles = theme => ({ + card: { + display: 'flex', + width: '100%' + }, + cardDetails: { + display: 'flex', + flex: 1 + }, + cardContent: { + flex: 1 + }, + cardMedia: { + flex: 1, + width: 160, + height: 160, + justifyContent: 'flex-start' + } +}) + +const CreateTeamWrapper = ({ classes }) => ( + + + +
+ + + +
+
+
+
+) + +CreateTeamWrapper.propTypes = { + classes: PropTypes.object.isRequired +} + +export default withStyles(styles)(CreateTeamWrapper) diff --git a/client/src/views/dashboard/components/DashTeam.js b/client/src/views/dashboard/components/DashTeam.js index f46bb6e30..39aef9fad 100644 --- a/client/src/views/dashboard/components/DashTeam.js +++ b/client/src/views/dashboard/components/DashTeam.js @@ -5,27 +5,29 @@ import { withStateHandlers, lifecycle, compose } from 'recompose' import Typography from '@material-ui/core/Typography' import Grid from '@material-ui/core/Grid' +import Card from '@material-ui/core/Card' +import CardContent from '@material-ui/core/CardContent' import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery' import DashTeamItem from './DashTeamItem' +import CreateTeamWrapper from './CreateTeamWrapper' +import { checkGraphQLError } from '../../../utils/graphql-errors' import { isDefined, isString } from '../../../utils/js-helpers' import { getItem } from '../../../utils/local-storage' -export const DashTeam = ({ user = null }) => { - console.log('DashTeam 1: ', user) +export const DashTeam = ({ classes, user = null }) => { let owner let loader let authId = null if (user !== null && isString(user)) { owner = JSON.parse(user) - if (isDefined(owner.sub)) authId = owner.sub + if (isDefined(owner.authId)) authId = owner.authId } else { loader = (Loading...) } - console.log('DashTeam 2: ', owner, authId) if (authId === null) { return ( @@ -47,21 +49,30 @@ export const DashTeam = ({ user = null }) => { let errors let queryLoader if (error) { - errors = error.graphQLErrors.map(({ message }, i) => ( - {message} - )) + errors = error.graphQLErrors.map(({ message }, i) => { + const displayMessage = checkGraphQLError(message) + return ( + {displayMessage} + ) + }) } if (!loading) { - return ( - - {!loading && data.teamsByOwner.edges.map(team => ( - - ))} - {queryLoader} - {errors} - {loader} - - ) + if (data.teamsByOwner.edges.length > 0) { + return ( + + {!loading && data.teamsByOwner.edges.map(team => ( + + ))} + {queryLoader} + {errors} + {loader} + + ) + } else { + return ( + + ) + } } else { return ( @@ -80,7 +91,8 @@ export const DashTeam = ({ user = null }) => { } DashTeam.propTypes = { - user: PropTypes.any + user: PropTypes.any, + classes: PropTypes.object.isRequired } const getUserOnMount = lifecycle({ From 758e5bdb83a9eea2b04898343d3634134fda380b Mon Sep 17 00:00:00 2001 From: Barry Low Date: Thu, 13 Sep 2018 23:55:57 -0700 Subject: [PATCH 06/16] Server: Fix Mutation authorization --- api/src/auth/authDirectives.js | 4 +- api/src/auth/middleware/getMember.js | 4 +- api/src/auth/middleware/jwt.js | 2 +- api/src/index.js | 74 +++++++++---------- api/src/schema.graphql | 2 +- client/src/auth/index.js | 8 +- .../src/graphql/teams/GetTeamsByOwnerQuery.js | 46 ++++++------ .../views/dashboard/components/CreateTeam.js | 22 +++--- .../views/dashboard/components/DashTeam.js | 19 ++--- 9 files changed, 88 insertions(+), 93 deletions(-) diff --git a/api/src/auth/authDirectives.js b/api/src/auth/authDirectives.js index f098fa4ec..471be4692 100644 --- a/api/src/auth/authDirectives.js +++ b/api/src/auth/authDirectives.js @@ -1,7 +1,7 @@ const _get = require('lodash.get') const { validateIdToken } = require('./validateIdToken') -const memberLocationOnContext = 'request.member' +const memberLocationOnContext = 'request.user' const bearerAccessToken = 'request.headers.authorization' const ctxMember = ctx => _get(ctx, memberLocationOnContext) @@ -29,7 +29,7 @@ const isLoggedIn = async ctx => { let member = ctxMember(ctx, memberLocationOnContext) let token = ctxToken(ctx, bearerAccessToken) let memberToken - console.log('isLoggedIn: ', member, token) + console.log('isLoggedIn: ', ctx, member, token) if (!member && token) { let scheme, credentials const tokenParts = token.split(' ') diff --git a/api/src/auth/middleware/getMember.js b/api/src/auth/middleware/getMember.js index 7b2642c50..7d19b2d6c 100644 --- a/api/src/auth/middleware/getMember.js +++ b/api/src/auth/middleware/getMember.js @@ -1,9 +1,9 @@ const getMember = async (req, res, next, db) => { if (!req.user) return next() const member = await db.query.member({ - where: { auth0id: req.user.sub } + where: { authId: req.user.sub } }) - req.user = { token: req.user, ...member } + req.user = { user: member } next() } diff --git a/api/src/auth/middleware/jwt.js b/api/src/auth/middleware/jwt.js index 39e8ecbe3..0ff677156 100644 --- a/api/src/auth/middleware/jwt.js +++ b/api/src/auth/middleware/jwt.js @@ -21,4 +21,4 @@ const checkJwt = jwt({ algorithms: [`RS256`] }) -module.exports = { checkJwt } +module.exports = checkJwt diff --git a/api/src/index.js b/api/src/index.js index a6598ea9b..9782f24b9 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -7,7 +7,8 @@ const { } = require('prisma-binding') const { makeExecutableSchema } = require('graphql-tools') const { importSchema } = require('graphql-import') -const { checkJwt } = require('./auth/middleware/jwt') + +const checkJwt = require('./auth/middleware/jwt') const { getMember } = require('./auth/middleware/getMember') const { validateIdToken } = require('./auth/validateIdToken') const { directiveResolvers } = require('./auth/authDirectives') @@ -30,7 +31,7 @@ const createMember = async function (ctx, info, idToken) { return member } -const ctxMember = ctx => ctx.request.member +const ctxMember = ctx => ctx.request.user const resolvers = { Query: { @@ -82,35 +83,32 @@ const resolvers = { return ctx.db.query.team({ where: { name: name } }, `{ name }`) }, async teamsByOwner(parent, { ownerId }, ctx, info) { - return ctx.db.query.teamsConnection({where: { owner: { authId: ownerId }}}, + console.log('teamsByOwner: ', ctx.user) + return ctx.db.query.teams({where: { owner: ownerId }}, `{ - edges { - node { - id - name - slug - owner - status { - status - reason - createdAt - } + id + name + slug + owner + status { + status + reason createdAt - profile { - avatar - description - motto - updatedAt - } - members { - role - member { - alias - authId - } + } + createdAt + profile { + avatar + description + motto + updatedAt + } + members { + role + member { + alias + authId } } - } }`) }, async owner(parent, args, ctx, info) { @@ -189,25 +187,27 @@ const schema = makeExecutableSchema({ const server = new GraphQLServer({ schema, context: req => ({ - ...req, - db + token: req.headers, + user: req.user, + db, + ...req }), }) server.express.use( server.options.endpoint, checkJwt, - (err, req, res, next) => { - console.log('checkJwt: ', err, req.user) - if (err) return res.status(401).send(err.message) - next() + function (err, req, res, next) { + console.log('checkJwt: ', err, req) + if (err) { + return res.status(201).send(err.message) + } else { + next() + } } ) -server.express.post(server.options.endpoint, (err, req, res, done) => { - console.log('getMember: ', err, req.user) - getMember(req, res, done, db) -}) +server.express.post(server.options.endpoint, (req, res, done) => getUser(req, res, done, db)) const whitelist = [ 'http://localhost:3000', diff --git a/api/src/schema.graphql b/api/src/schema.graphql index f63570229..9e315174c 100644 --- a/api/src/schema.graphql +++ b/api/src/schema.graphql @@ -10,7 +10,7 @@ type Query { teamDetails: [Team!]! @isAuthenticated teamByName(name: String!): Team teamById(teamId: String!): Team - teamsByOwner(ownerId: String!): TeamConnection + teamsByOwner(ownerId: String!): [Team!]! @isAuthenticated owner: Member @isAuthenticated currentMember: Member @isAuthenticated member(authId: String!): Member @isAuthenticated diff --git a/client/src/auth/index.js b/client/src/auth/index.js index 05ea56a26..b1e788a86 100644 --- a/client/src/auth/index.js +++ b/client/src/auth/index.js @@ -103,7 +103,7 @@ class Auth { this.cb(data) console.log(authResult.idTokenPayload) const user = { - authID: authResult.idTokenPayload.sub, + authId: authResult.idTokenPayload.sub, alias: authResult.idTokenPayload.nickname } setItem('user', JSON.stringify(user)) @@ -131,8 +131,8 @@ class Auth { console.log('signinOrCreateAccount auth: ', await data) const user = { - authID: data.data.authenticate.authId, - alias: data.data.authenticate.authId.alias + authId: data.data.authenticate.authId, + alias: data.data.authenticate.alias } setItem('user', JSON.stringify(user)) if (window.location.href.includes(`callback`)) { @@ -176,7 +176,7 @@ class Auth { .then(result => { console.log('handleAuth.checksessions: ', result) const user = { - authID: result.idTokenPayload.sub, + authId: result.idTokenPayload.sub, alias: result.idTokenPayload.nickname } setItem('user', JSON.stringify(user)) diff --git a/client/src/graphql/teams/GetTeamsByOwnerQuery.js b/client/src/graphql/teams/GetTeamsByOwnerQuery.js index f5b2f327a..d2f60c882 100644 --- a/client/src/graphql/teams/GetTeamsByOwnerQuery.js +++ b/client/src/graphql/teams/GetTeamsByOwnerQuery.js @@ -4,31 +4,27 @@ import gql from 'graphql-tag' export const GET_TEAMS_BY_OWNER = gql` query teamsByOwnerQuery($authId: String!) { teamsByOwner(ownerId: $authId) { - edges { - node { - id - name - slug - owner - status { - status - reason - createdAt - } - createdAt - profile { - avatar - description - motto - updatedAt - } - members { - role - member { - alias - authId - } - } + id + name + slug + owner + status { + status + reason + createdAt + } + createdAt + profile { + avatar + description + motto + updatedAt + } + members { + role + member { + alias + authId } } } diff --git a/client/src/views/dashboard/components/CreateTeam.js b/client/src/views/dashboard/components/CreateTeam.js index b01184b7d..c4d884672 100644 --- a/client/src/views/dashboard/components/CreateTeam.js +++ b/client/src/views/dashboard/components/CreateTeam.js @@ -4,6 +4,7 @@ import { Mutation } from 'react-apollo' import Typography from '@material-ui/core/Typography' import { getItem } from '../../../utils/local-storage' +import { checkGraphQLError } from '../../../utils/graphql-errors' import CREATE_TEAM from '../../../graphql/teams/CreateTeamMutation' import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery' @@ -15,11 +16,10 @@ const CreateTeam = () => { { - const { teamsByOwner } = cache.readQuery({ query: GET_TEAMS_BY_OWNER }) - cache.writeQuery({ - query: GET_TEAMS_BY_OWNER, - data: { teamsByOwner: teamsByOwner.concat([createTeam]) } - }) + const data = cache.readQuery({ query: GET_TEAMS_BY_OWNER }) + console.log('Mutation cache update: ', createTeam, data) + data.getTeamsByOwner.push(createTeam) + cache.writeQuery({ query: GET_TEAMS_BY_OWNER, data }) }} > {(createTeam, { loading, error, data }) => { @@ -29,9 +29,13 @@ const CreateTeam = () => { loader = (Submitting team...) } if (error) { - errors = error.graphQLErrors.map(({ message }, i) => ( - {message} - )) + errors = error.graphQLErrors.map(({ message }, i) => { + const displayMessage = checkGraphQLError(message) + console.log('createTeam error:', displayMessage) + return ( + {message} + ) + }) } return (
@@ -60,7 +64,7 @@ const handleSubmit = async (e, createTeam, input) => { e.preventDefault() const currentUser = await getItem('user') let authId = JSON.parse(currentUser) - authId = authId.sub + authId = authId.authId const name = input.value const slug = slugify(name) await createTeam({ variables: { name, slug, owner: authId } }) diff --git a/client/src/views/dashboard/components/DashTeam.js b/client/src/views/dashboard/components/DashTeam.js index 39aef9fad..8be96d370 100644 --- a/client/src/views/dashboard/components/DashTeam.js +++ b/client/src/views/dashboard/components/DashTeam.js @@ -5,15 +5,12 @@ import { withStateHandlers, lifecycle, compose } from 'recompose' import Typography from '@material-ui/core/Typography' import Grid from '@material-ui/core/Grid' -import Card from '@material-ui/core/Card' -import CardContent from '@material-ui/core/CardContent' import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery' import DashTeamItem from './DashTeamItem' import CreateTeamWrapper from './CreateTeamWrapper' -import { checkGraphQLError } from '../../../utils/graphql-errors' import { isDefined, isString } from '../../../utils/js-helpers' import { getItem } from '../../../utils/local-storage' @@ -21,12 +18,14 @@ export const DashTeam = ({ classes, user = null }) => { let owner let loader let authId = null + console.log('DashTeam: ', user) if (user !== null && isString(user)) { owner = JSON.parse(user) if (isDefined(owner.authId)) authId = owner.authId } else { loader = (Loading...) } + console.log('DashTeam 2: ', owner, authId) if (authId === null) { return ( @@ -43,6 +42,7 @@ export const DashTeam = ({ classes, user = null }) => { Teams + {({ loading, error, data }) => { console.log('GET_TEAMS_BY_OWNER: ', loading, error, data) @@ -50,17 +50,16 @@ export const DashTeam = ({ classes, user = null }) => { let queryLoader if (error) { errors = error.graphQLErrors.map(({ message }, i) => { - const displayMessage = checkGraphQLError(message) return ( - {displayMessage} + {message} ) }) } - if (!loading) { - if (data.teamsByOwner.edges.length > 0) { + if (!loading && !error) { + if (data.teamsByOwner.length > 0) { return ( - {!loading && data.teamsByOwner.edges.map(team => ( + {!loading && data.teamsByOwner.map(team => ( ))} {queryLoader} @@ -68,10 +67,6 @@ export const DashTeam = ({ classes, user = null }) => { {loader} ) - } else { - return ( - - ) } } else { return ( From ba5a321127e4c2b48a8b28ae5e7a160ba5de0932 Mon Sep 17 00:00:00 2001 From: Barry Low Date: Fri, 14 Sep 2018 01:14:24 -0700 Subject: [PATCH 07/16] Client: Teams page basic --- api/package-lock.json | 31 +++-- api/package.json | 1 + api/src/graphql/TeamsFragment.js | 29 +++++ api/src/index.js | 37 +----- client/src/App.js | 2 + client/src/auth/index.js | 7 +- client/src/graphql/teams/GetAllTeamsQuery.js | 4 +- client/src/graphql/teams/Teams.js | 48 ++++---- client/src/utils/graphql-errors.js | 2 +- .../views/dashboard/components/CreateTeam.js | 6 +- .../views/dashboard/components/DashTeam.js | 21 ++-- .../dashboard/components/DashTeamItem.js | 9 +- .../src/views/teams/components/TeamsItem.js | 111 ++++++++++++++++++ .../src/views/teams/components/TeamsList.js | 61 ++++++++++ client/src/views/teams/index.js | 12 +- 15 files changed, 286 insertions(+), 95 deletions(-) create mode 100644 api/src/graphql/TeamsFragment.js create mode 100644 client/src/views/teams/components/TeamsItem.js create mode 100644 client/src/views/teams/components/TeamsList.js diff --git a/api/package-lock.json b/api/package-lock.json index d43af47d4..81ed969ea 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -568,7 +568,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -614,7 +614,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -923,7 +923,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -1462,7 +1462,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -1640,7 +1640,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -4084,6 +4084,11 @@ "iterall": "^1.2.1" } }, + "graphql-tag": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.9.2.tgz", + "integrity": "sha512-qnNmof9pAqj/LUzs3lStP0Gw1qhdVCUS7Ab7+SUB6KD5aX1uqxWQRwMnOGTkhKuLvLNIs1TvNz+iS9kUGl1MhA==" + }, "graphql-tools": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/graphql-tools/-/graphql-tools-3.1.1.tgz", @@ -4997,7 +5002,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -5366,7 +5371,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -6693,7 +6698,7 @@ }, "graphql-import": { "version": "0.4.5", - "resolved": "http://registry.npmjs.org/graphql-import/-/graphql-import-0.4.5.tgz", + "resolved": "https://registry.npmjs.org/graphql-import/-/graphql-import-0.4.5.tgz", "integrity": "sha512-G/+I08Qp6/QGTb9qapknCm3yPHV0ZL7wbaalWFpxsfR8ZhZoTBe//LsbsCKlbALQpcMegchpJhpTSKiJjhaVqQ==", "dev": true, "requires": { @@ -7590,7 +7595,7 @@ "dependencies": { "commander": { "version": "2.8.1", - "resolved": "http://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", "dev": true, "requires": { @@ -8178,7 +8183,7 @@ }, "table": { "version": "4.0.3", - "resolved": "http://registry.npmjs.org/table/-/table-4.0.3.tgz", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.3.tgz", "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==", "dev": true, "requires": { @@ -8239,7 +8244,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -8504,7 +8509,7 @@ }, "buffer": { "version": "3.6.0", - "resolved": "http://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", "integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=", "dev": true, "requires": { @@ -9087,7 +9092,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { diff --git a/api/package.json b/api/package.json index 8bc857126..784b66264 100644 --- a/api/package.json +++ b/api/package.json @@ -11,6 +11,7 @@ "dotenv": "^6.0.0", "express-jwt": "^5.3.1", "graphql-import": "^0.6.0", + "graphql-tag": "^2.9.2", "graphql-tools": "3.1.1", "graphql-yoga": "^1.16.1", "jsonwebtoken": "^8.3.0", diff --git a/api/src/graphql/TeamsFragment.js b/api/src/graphql/TeamsFragment.js new file mode 100644 index 000000000..e75ce8382 --- /dev/null +++ b/api/src/graphql/TeamsFragment.js @@ -0,0 +1,29 @@ +const gql = require('graphql-tag') + +const TEAMS_FRAGMENT = gql`{ + id + name + slug + owner + status { + status + reason + createdAt + } + createdAt + profile { + avatar + description + motto + updatedAt + } + members { + role + member { + alias + authId + } + } +}` + +module.exports = TEAMS_FRAGMENT diff --git a/api/src/index.js b/api/src/index.js index 9782f24b9..0386ba61b 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -13,6 +13,8 @@ const { getMember } = require('./auth/middleware/getMember') const { validateIdToken } = require('./auth/validateIdToken') const { directiveResolvers } = require('./auth/authDirectives') +const TEAMS_FRAGMENT = require('./graphql/TeamsFragment') + const createMember = async function (ctx, info, idToken) { console.log('createMember', idToken) const member = await ctx.db.mutation.upsertMember({ @@ -84,32 +86,7 @@ const resolvers = { }, async teamsByOwner(parent, { ownerId }, ctx, info) { console.log('teamsByOwner: ', ctx.user) - return ctx.db.query.teams({where: { owner: ownerId }}, - `{ - id - name - slug - owner - status { - status - reason - createdAt - } - createdAt - profile { - avatar - description - motto - updatedAt - } - members { - role - member { - alias - authId - } - } - }`) + return ctx.db.query.teams({where: { owner: ownerId }}, TEAMS_FRAGMENT) }, async owner(parent, args, ctx, info) { console.log('resolver.query.owner ctx: ', ctxMember(ctx)) @@ -145,13 +122,7 @@ const resolvers = { return member }, async createTeam(parent, { name, slug, owner }, ctx, info) { - return ctx.db.mutation.createTeam({ - data: { - name: name, - slug: slug, - owner: owner - } - }, info) + return ctx.db.mutation.createTeam({ data: { name: name, slug: slug, owner: owner, members: { create: { member:{ connect:{ authId: owner} }, role: 'OWNER' } } } }, TEAMS_FRAGMENT) .catch((err) => { console.log('createTeam error: ', err) return err diff --git a/client/src/App.js b/client/src/App.js index adf708aa3..e2f28ac3c 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -21,6 +21,7 @@ import { Callback, Home, Dashboard, + Teams, theme, globalStyles } from './views' @@ -148,6 +149,7 @@ class App extends Component { + { +export const checkGraphQLError = error => { console.log('checkGraphQLError ', ErrorResponse) if (error.search(/unique constraint/)) { const field = error.substring(error.indexOf('=') + 1) diff --git a/client/src/views/dashboard/components/CreateTeam.js b/client/src/views/dashboard/components/CreateTeam.js index c4d884672..90cac23f7 100644 --- a/client/src/views/dashboard/components/CreateTeam.js +++ b/client/src/views/dashboard/components/CreateTeam.js @@ -26,14 +26,16 @@ const CreateTeam = () => { let errors let loader if (loading) { - loader = (Submitting team...) + loader = Submitting team... } if (error) { errors = error.graphQLErrors.map(({ message }, i) => { const displayMessage = checkGraphQLError(message) console.log('createTeam error:', displayMessage) return ( - {message} + + {message} + ) }) } diff --git a/client/src/views/dashboard/components/DashTeam.js b/client/src/views/dashboard/components/DashTeam.js index 8be96d370..d8b2df1ce 100644 --- a/client/src/views/dashboard/components/DashTeam.js +++ b/client/src/views/dashboard/components/DashTeam.js @@ -23,7 +23,7 @@ export const DashTeam = ({ classes, user = null }) => { owner = JSON.parse(user) if (isDefined(owner.authId)) authId = owner.authId } else { - loader = (Loading...) + loader = Loading... } console.log('DashTeam 2: ', owner, authId) @@ -51,7 +51,9 @@ export const DashTeam = ({ classes, user = null }) => { if (error) { errors = error.graphQLErrors.map(({ message }, i) => { return ( - {message} + + {message} + ) }) } @@ -59,9 +61,10 @@ export const DashTeam = ({ classes, user = null }) => { if (data.teamsByOwner.length > 0) { return ( - {!loading && data.teamsByOwner.map(team => ( - - ))} + {!loading && + data.teamsByOwner.map(team => ( + + ))} {queryLoader} {errors} {loader} @@ -98,11 +101,9 @@ const getUserOnMount = lifecycle({ } }) -const mapStateToProps = withStateHandlers( - () => ({ user: null }), { - user: ({ user }) => () => ({ user }) - } -) +const mapStateToProps = withStateHandlers(() => ({ user: null }), { + user: ({ user }) => () => ({ user }) +}) const DashTeamAuthId = compose( mapStateToProps, diff --git a/client/src/views/dashboard/components/DashTeamItem.js b/client/src/views/dashboard/components/DashTeamItem.js index cdf585c8f..1de33a7a4 100644 --- a/client/src/views/dashboard/components/DashTeamItem.js +++ b/client/src/views/dashboard/components/DashTeamItem.js @@ -34,7 +34,7 @@ const styles = theme => ({ } }) -export const DashTeamItem = ({ classes }) => ( +export const DashTeamItem = ({ classes, team }) => (
@@ -44,9 +44,9 @@ export const DashTeamItem = ({ classes }) => ( title='Image title' /> - Goodester + {team.name} - 09.15.2018 + {team.createdAt} Members:6 @@ -66,7 +66,8 @@ export const DashTeamItem = ({ classes }) => ( ) DashTeamItem.propTypes = { - classes: PropTypes.object.isRequired + classes: PropTypes.object.isRequired, + team: PropTypes.object.isRequired } export default withStyles(styles)(DashTeamItem) diff --git a/client/src/views/teams/components/TeamsItem.js b/client/src/views/teams/components/TeamsItem.js new file mode 100644 index 000000000..16d833c32 --- /dev/null +++ b/client/src/views/teams/components/TeamsItem.js @@ -0,0 +1,111 @@ +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 Paper from '@material-ui/core/Paper' +import Button from '@material-ui/core/Button' +import ButtonBase from '@material-ui/core/ButtonBase' + +const styles = theme => ({ + layout: { + width: 'auto', + marginLeft: theme.spacing.unit * 2, + marginRight: theme.spacing.unit * 2, + [theme.breakpoints.up(600 + theme.spacing.unit * 2 * 2)]: { + width: 600, + marginLeft: 'auto', + marginRight: 'auto' + } + }, + paper: { + marginTop: theme.spacing.unit * 0.1, + marginBottom: theme.spacing.unit * 0.1, + padding: theme.spacing.unit * 2, + [theme.breakpoints.up(600 + theme.spacing.unit * 3 * 2)]: { + marginTop: theme.spacing.unit * 1, + marginBottom: theme.spacing.unit * 1, + padding: theme.spacing.unit * 3 + } + }, + card: { + display: 'block', + width: '100%' + }, + cardDetails: { + display: 'flex', + flex: 1 + }, + cardContent: { + flex: 1 + }, + buttonRight: { + justifyContent: 'flex-end' + }, + image: { + width: 140, + height: 140 + }, + img: { + margin: 'auto', + display: 'block', + maxWidth: '100%', + maxHeight: '100%' + } +}) + +export const TeamsItem = ({ classes, team }) => ( + +
+ + + + + complex + + + + + + {team.name} + + {team.createdAt} + + + Members: 1 + + + + + Now recruiting! + + + + + + + + + +
+
+) + +TeamsItem.propTypes = { + classes: PropTypes.object.isRequired, + team: PropTypes.object.isRequired +} + +export default withStyles(styles)(TeamsItem) diff --git a/client/src/views/teams/components/TeamsList.js b/client/src/views/teams/components/TeamsList.js new file mode 100644 index 000000000..c156b244b --- /dev/null +++ b/client/src/views/teams/components/TeamsList.js @@ -0,0 +1,61 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { Query } from 'react-apollo' + +import Typography from '@material-ui/core/Typography' +import Grid from '@material-ui/core/Grid' + +import GET_ALL_TEAMS_QUERY from '../../../graphql/teams/GetAllTeamsQuery' + +import TeamsItem from './TeamsItem' + +export const TeamsList = ({ classes }) => ( + + + {({ loading, error, data }) => { + console.log('GET_TEAMS_BY_OWNER: ', loading, error, data) + let errors + let queryLoader + if (error) { + errors = error.graphQLErrors.map(({ message }, i) => { + return ( + + {message} + + ) + }) + } + if (!loading && !error) { + if (data.teams.edges.length > 0) { + return ( + + {!loading && + data.teams.edges.map(team => ( + + ))} + {queryLoader} + {errors} + + ) + } + } else { + return ( + + + Loading... + + {queryLoader} + {errors} + + ) + } + }} + + +) + +TeamsList.propTypes = { + classes: PropTypes.object.isRequired +} + +export default TeamsList diff --git a/client/src/views/teams/index.js b/client/src/views/teams/index.js index 69dbd99aa..96fd0e5c8 100644 --- a/client/src/views/teams/index.js +++ b/client/src/views/teams/index.js @@ -3,8 +3,11 @@ import PropTypes from 'prop-types' import CssBaseline from '@material-ui/core/CssBaseline' import Typography from '@material-ui/core/Typography' +import Grid from '@material-ui/core/Grid' import { withStyles } from '@material-ui/core/styles' +import TeamsList from './components/TeamsList' + const styles = theme => ({ '@global': { body: { @@ -28,7 +31,7 @@ const styles = theme => ({ } }) -const Home = ({ classes }) => ( +const Teams = ({ classes }) => (
@@ -41,13 +44,16 @@ const Home = ({ classes }) => ( > Teams + + +
) -Home.propTypes = { +Teams.propTypes = { classes: PropTypes.object.isRequired } -export default withStyles(styles)(Home) +export default withStyles(styles)(Teams) From 5b90eb8923b436133fbfaf6d28a8d90ebe40a40c Mon Sep 17 00:00:00 2001 From: Barry Low Date: Fri, 14 Sep 2018 07:35:25 -0700 Subject: [PATCH 08/16] Client: Team Details subpage --- client/src/App.js | 1 + .../views/teams/components/TeamsDetails.js | 89 +++++++++++ .../src/views/teams/components/TeamsItem.js | 134 +++++----------- .../src/views/teams/components/TeamsList.js | 143 +++++++++++++----- client/src/views/teams/index.js | 30 +--- 5 files changed, 242 insertions(+), 155 deletions(-) create mode 100644 client/src/views/teams/components/TeamsDetails.js diff --git a/client/src/App.js b/client/src/App.js index e2f28ac3c..241fa8d1b 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -150,6 +150,7 @@ class App extends Component { + ({ + 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(900 + theme.spacing.unit * 3 * 2)]: { + width: 900, + marginLeft: 'auto', + marginRight: 'auto' + } + }, + paper: { + marginTop: theme.spacing.unit * 3, + marginBottom: theme.spacing.unit * 3, + padding: theme.spacing.unit * 2, + [theme.breakpoints.up(600 + theme.spacing.unit * 3 * 2)]: { + marginTop: theme.spacing.unit * 6, + marginBottom: theme.spacing.unit * 6, + padding: theme.spacing.unit * 3 + } + }, + heroContent: { + maxWidth: 600, + margin: '0 auto', + padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px` + } +}) + +const TeamsDetails = ({ classes, team }) => ( + + +
+ +
+ ← Back to all teams + + {team.name} + + + {team.createdAt} + + + Members: {team.members.length} + + + Team Admin: + { + team.members.map(member => { + if (member.role === 'OWNER' || member.role === 'ADMIN') { + return member.member.alias + } + }) + } + +
+
+
+
+) +TeamsDetails.propTypes = { + classes: PropTypes.object.isRequired, + team: PropTypes.object.isRequired +} + +export default withStyles(styles)(TeamsDetails) diff --git a/client/src/views/teams/components/TeamsItem.js b/client/src/views/teams/components/TeamsItem.js index 16d833c32..6b2e20bb1 100644 --- a/client/src/views/teams/components/TeamsItem.js +++ b/client/src/views/teams/components/TeamsItem.js @@ -1,105 +1,49 @@ 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 Paper from '@material-ui/core/Paper' +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 ButtonBase from '@material-ui/core/ButtonBase' +import Typography from '@material-ui/core/Typography' -const styles = theme => ({ - layout: { - width: 'auto', - marginLeft: theme.spacing.unit * 2, - marginRight: theme.spacing.unit * 2, - [theme.breakpoints.up(600 + theme.spacing.unit * 2 * 2)]: { - width: 600, - marginLeft: 'auto', - marginRight: 'auto' - } - }, - paper: { - marginTop: theme.spacing.unit * 0.1, - marginBottom: theme.spacing.unit * 0.1, - padding: theme.spacing.unit * 2, - [theme.breakpoints.up(600 + theme.spacing.unit * 3 * 2)]: { - marginTop: theme.spacing.unit * 1, - marginBottom: theme.spacing.unit * 1, - padding: theme.spacing.unit * 3 - } - }, - card: { - display: 'block', - width: '100%' - }, - cardDetails: { - display: 'flex', - flex: 1 - }, - cardContent: { - flex: 1 - }, - buttonRight: { - justifyContent: 'flex-end' - }, - image: { - width: 140, - height: 140 - }, - img: { - margin: 'auto', - display: 'block', - maxWidth: '100%', - maxHeight: '100%' - } -}) +import { Link } from 'react-router-dom' export const TeamsItem = ({ classes, team }) => ( - -
- - - - - complex - - - - - - {team.name} - - {team.createdAt} - - - Members: 1 - - - - - Now recruiting! - - - - - - - - - -
+ + + + + + + {team.name} + + + {team.createdAt} + + + Members: 1 + + + Now recruiting! + + + + + + + + + ) @@ -108,4 +52,4 @@ TeamsItem.propTypes = { team: PropTypes.object.isRequired } -export default withStyles(styles)(TeamsItem) +export default TeamsItem diff --git a/client/src/views/teams/components/TeamsList.js b/client/src/views/teams/components/TeamsList.js index c156b244b..8ae962ead 100644 --- a/client/src/views/teams/components/TeamsList.js +++ b/client/src/views/teams/components/TeamsList.js @@ -4,58 +4,125 @@ import { Query } from 'react-apollo' import Typography from '@material-ui/core/Typography' import Grid from '@material-ui/core/Grid' +import { withStyles } from '@material-ui/core/styles' import GET_ALL_TEAMS_QUERY from '../../../graphql/teams/GetAllTeamsQuery' -import TeamsItem from './TeamsItem' +import { isEmpty } from '../../../utils/js-helpers' -export const TeamsList = ({ classes }) => ( - - - {({ loading, error, data }) => { - console.log('GET_TEAMS_BY_OWNER: ', loading, error, data) - let errors - let queryLoader - if (error) { - errors = error.graphQLErrors.map(({ message }, i) => { +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: '56.25%' // 16:9 + }, + cardContent: { + flexGrow: 1 + }, + buttonRight: { + justifyContent: 'flex-end' + } +}) + +export const TeamsList = ({ classes, match }) => ( + + {({ loading, error, data }) => { + console.log('GET_TEAMS_BY_OWNER: ', loading, error, data, match) + let slug = null + if (!isEmpty(match.params) && match.params.slug) slug = match.params.slug + + let errors + let queryLoader + if (error) { + errors = error.graphQLErrors.map(({ message }, i) => { + return ( + + {message} + + ) + }) + } + if (!loading && !error) { + if (data.teams.edges.length > 0) { + if (slug !== null) { return ( - - {message} - - ) - }) - } - if (!loading && !error) { - if (data.teams.edges.length > 0) { - return ( - + {!loading && - data.teams.edges.map(team => ( - - ))} + data.teams.edges.map(team => { + if (team.node.slug === slug) { + return ( + + ) + } + })} {queryLoader} {errors} ) + } else { + return ( + +
+ + Teams + +
+ + {!loading && + data.teams.edges.map(team => ( + + ))} + {queryLoader} + {errors} + +
+ ) } - } else { - return ( - - - Loading... - - {queryLoader} - {errors} - - ) } - }} -
-
+ } else { + return ( + + + Loading... + + {queryLoader} + {errors} + + ) + } + }} +
) TeamsList.propTypes = { - classes: PropTypes.object.isRequired + classes: PropTypes.object.isRequired, + match: PropTypes.object } -export default TeamsList +export default withStyles(styles)(TeamsList) diff --git a/client/src/views/teams/index.js b/client/src/views/teams/index.js index 96fd0e5c8..3c2087d83 100644 --- a/client/src/views/teams/index.js +++ b/client/src/views/teams/index.js @@ -2,13 +2,14 @@ import React from 'react' import PropTypes from 'prop-types' import CssBaseline from '@material-ui/core/CssBaseline' -import Typography from '@material-ui/core/Typography' -import Grid from '@material-ui/core/Grid' import { withStyles } from '@material-ui/core/styles' import TeamsList from './components/TeamsList' const styles = theme => ({ + root: { + flexGrow: 1 + }, '@global': { body: { backgroundColor: theme.palette.common.white @@ -18,42 +19,27 @@ const styles = theme => ({ width: 'auto', marginLeft: theme.spacing.unit * 3, marginRight: theme.spacing.unit * 3, + marginBottom: theme.spacing.unit * 6, [theme.breakpoints.up(900 + theme.spacing.unit * 3 * 2)]: { width: 900, marginLeft: 'auto', marginRight: 'auto' } - }, - heroContent: { - maxWidth: 600, - margin: '0 auto', - padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px` } }) -const Teams = ({ classes }) => ( +const Teams = ({ classes, match }) => (
-
- - Teams - - - - -
+
) Teams.propTypes = { - classes: PropTypes.object.isRequired + classes: PropTypes.object.isRequired, + match: PropTypes.object } export default withStyles(styles)(Teams) From f2aae81f6ecbfad2d5b845b0490740c0354b8fdb Mon Sep 17 00:00:00 2001 From: Barry Low Date: Fri, 14 Sep 2018 07:56:51 -0700 Subject: [PATCH 09/16] Add basic Team Management --- api/src/graphql/TeamsConnectionsFragment.js | 33 +++++ api/src/index.js | 39 ++--- api/src/schema.graphql | 3 +- .../teams/UpdateTeamProfileMutation.js | 34 +++++ client/src/views/dashboard/ManageTeams.js | 6 +- .../dashboard/components/ManageTeamEdit.js | 133 ++++++++++++++++++ .../components/ManageTeamsDetails.js | 89 ++++++++++++ .../dashboard/components/ManageTeamsItem.js | 55 ++++++++ .../dashboard/components/ManageTeamsList.js | 128 +++++++++++++++++ .../src/views/teams/components/TeamsList.js | 2 +- 10 files changed, 487 insertions(+), 35 deletions(-) create mode 100644 api/src/graphql/TeamsConnectionsFragment.js create mode 100644 client/src/graphql/teams/UpdateTeamProfileMutation.js create mode 100644 client/src/views/dashboard/components/ManageTeamEdit.js create mode 100644 client/src/views/dashboard/components/ManageTeamsDetails.js create mode 100644 client/src/views/dashboard/components/ManageTeamsItem.js create mode 100644 client/src/views/dashboard/components/ManageTeamsList.js diff --git a/api/src/graphql/TeamsConnectionsFragment.js b/api/src/graphql/TeamsConnectionsFragment.js new file mode 100644 index 000000000..89a22a8c4 --- /dev/null +++ b/api/src/graphql/TeamsConnectionsFragment.js @@ -0,0 +1,33 @@ +const gql = require('graphql-tag') + +const TEAMS_CONNECTIONS_FRAGMENT = gql`{ + edges { + node { + id + name + slug + owner + status { + status + reason + createdAt + } + createdAt + profile { + avatar + description + motto + updatedAt + } + members { + role + member { + alias + authId + } + } + } + } +}` + +module.exports = TEAMS_CONNECTIONS_FRAGMENT diff --git a/api/src/index.js b/api/src/index.js index 0386ba61b..6b4a5167d 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -14,6 +14,7 @@ const { validateIdToken } = require('./auth/validateIdToken') const { directiveResolvers } = require('./auth/authDirectives') const TEAMS_FRAGMENT = require('./graphql/TeamsFragment') +const TEAMS_CONNECTIONS_FRAGMENT = require('./graphql/TeamsConnectionsFragment') const createMember = async function (ctx, info, idToken) { console.log('createMember', idToken) @@ -47,36 +48,7 @@ const resolvers = { return ctx.db.query.member({ where: { authId } }, info) }, teams(parent, args, ctx, info) { - return ctx.db.query.teamsConnection({}, - `{ - edges { - node { - id - name - slug - owner - status { - status - reason - createdAt - } - createdAt - profile { - avatar - description - motto - updatedAt - } - members { - role - member { - alias - authId - } - } - } - } - }`) + return ctx.db.query.teamsConnection({}, TEAMS_CONNECTIONS_FRAGMENT) }, async teamById(parent, { id }, ctx, info) { return ctx.db.query.team({ where: { id } }, info) @@ -128,6 +100,13 @@ const resolvers = { return err }) }, + async updateTeamProfile(parent, { slug, owner, description, motto, avatar }, ctx, info) { + return ctx.db.mutation.updateTeam({data:{profile: {update: {description: description, motto: motto, avatar: avatar}}}, where:{slug: slug}}), TEAMS_FRAGMENT) + .catch((err) => { + console.log('createTeam error: ', err) + return err + }) + }, async deleteTeam(parent, { id }, ctx, info) { return ctx.db.mutation.deleteTeam({ where: { id } }, info) .catch((res) => { diff --git a/api/src/schema.graphql b/api/src/schema.graphql index 9e315174c..8b5d48d77 100644 --- a/api/src/schema.graphql +++ b/api/src/schema.graphql @@ -18,7 +18,8 @@ type Query { type Mutation { authenticate(idToken: String!): Member - createTeam(name: String!, slug: String, owner: String): Team @isAuthenticated + createTeam(name: String!, slug: String!, owner: String!): Team @isAuthenticated + updateTeamProfile(slug: String!, owner: String!, description: String, motto: String, avatar: String): Team @isAuthenticated deleteTeam(id: ID!): Team @isAuthenticated @isOwner(type: "Team") } diff --git a/client/src/graphql/teams/UpdateTeamProfileMutation.js b/client/src/graphql/teams/UpdateTeamProfileMutation.js new file mode 100644 index 000000000..6672a7a24 --- /dev/null +++ b/client/src/graphql/teams/UpdateTeamProfileMutation.js @@ -0,0 +1,34 @@ +/* eslint-disable no-unused-vars */ +import gql from 'graphql-tag' + +const CREATE_TEAM = gql` + mutation UpdateTeamMutation($slug: String!, $owner: String!, $description: String, $motto: String) { + createTeam(slug: $slug, owner: $owner, description: $description, motto: $motto) { + id + name + slug + owner + status { + status + reason + createdAt + } + createdAt + profile { + avatar + description + motto + updatedAt + } + members { + role + member { + alias + authId + } + } + } + } +` + +export default CREATE_TEAM diff --git a/client/src/views/dashboard/ManageTeams.js b/client/src/views/dashboard/ManageTeams.js index ecf65c9db..175c4aded 100644 --- a/client/src/views/dashboard/ManageTeams.js +++ b/client/src/views/dashboard/ManageTeams.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types' import Typography from '@material-ui/core/Typography' import { withStyles } from '@material-ui/core/styles' -import TeamTable from './components/TeamTable' +import ManageTeamsList from './components/ManageTeamsList' const styles = theme => ({ tableContainer: { @@ -15,10 +15,10 @@ const styles = theme => ({ const ManageTeams = ({ classes }) => (
- Teams + Manage Your Teams
- +
) diff --git a/client/src/views/dashboard/components/ManageTeamEdit.js b/client/src/views/dashboard/components/ManageTeamEdit.js new file mode 100644 index 000000000..d10dd5728 --- /dev/null +++ b/client/src/views/dashboard/components/ManageTeamEdit.js @@ -0,0 +1,133 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import { withRouter } from 'react-router-dom' +import Button from '@material-ui/core/Button' +import AddIcon from '@material-ui/icons/Add' +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 { getItem } from '../../../utils/local-storage' + +export class ManageTeamEdit extends Component { + constructor (props) { + super(props) + + this.handleClickOpen = this.handleClickOpen.bind(this) + this.handleClose = this.handleClose.bind(this) + this.handlePost = this.handlePost.bind(this) + this.slugify = this.slugify.bind(this) + this.handleChange = this.handleChange.bind(this) + + this.state = { + open: false, + motto: '', + description: '' + } + } + + 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.team) + return ( +
+ + + Edit Team Details + + Team Creation + Team Motto: + + + + + + + +
+ ) + } + + 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 + } + + async handlePost (e) { + e.preventDefault() + const { name } = this.state + const slug = this.slugify(name) + const currentUser = await getItem('user') + let authId = JSON.parse(currentUser) + authId = authId.sub + console.log('createPage cu:', JSON.parse(currentUser)) + await this.props.createTeamMutation({ + variables: { + name, + slug, + owner: authId + } + }) + this.setState({ open: false }) + } +} + +ManageTeamEdit.propTypes = { + classes: PropTypes.object.isRequired, + team: PropTypes.object.isRequired, + createTeamMutation: PropTypes.function +} + +export default withRouter(ManageTeamEdit) diff --git a/client/src/views/dashboard/components/ManageTeamsDetails.js b/client/src/views/dashboard/components/ManageTeamsDetails.js new file mode 100644 index 000000000..65a988215 --- /dev/null +++ b/client/src/views/dashboard/components/ManageTeamsDetails.js @@ -0,0 +1,89 @@ +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 { withStyles } from '@material-ui/core/styles' + +import { Link } from 'react-router-dom' + +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(900 + theme.spacing.unit * 3 * 2)]: { + width: 900, + marginLeft: 'auto', + marginRight: 'auto' + } + }, + paper: { + marginTop: theme.spacing.unit * 3, + marginBottom: theme.spacing.unit * 3, + padding: theme.spacing.unit * 2, + [theme.breakpoints.up(600 + theme.spacing.unit * 3 * 2)]: { + marginTop: theme.spacing.unit * 6, + marginBottom: theme.spacing.unit * 6, + padding: theme.spacing.unit * 3 + } + }, + heroContent: { + maxWidth: 600, + margin: '0 auto', + padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px` + } +}) + +const ManageTeamsDetails = ({ classes, team }) => ( + + +
+ +
+ ← Back to all teams + + {team.name} + + + {team.createdAt} + + + Members: {team.members.length} + + + Team Admin: + { + team.members.map(member => { + if (member.role === 'OWNER' || member.role === 'ADMIN') { + return member.member.alias + } + }) + } + +
+
+
+
+) +ManageTeamsDetails.propTypes = { + classes: PropTypes.object.isRequired, + team: PropTypes.object.isRequired +} + +export default withStyles(styles)(ManageTeamsDetails) diff --git a/client/src/views/dashboard/components/ManageTeamsItem.js b/client/src/views/dashboard/components/ManageTeamsItem.js new file mode 100644 index 000000000..7c00639d9 --- /dev/null +++ b/client/src/views/dashboard/components/ManageTeamsItem.js @@ -0,0 +1,55 @@ +import React from 'react' +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 { Link } from 'react-router-dom' + +export const ManageTeamsItem = ({ classes, team }) => ( + + + + + + + {team.name} + + + {team.createdAt} + + + Members: 1 + + + Now recruiting! + + + + + + + + + + +) + +ManageTeamsItem.propTypes = { + classes: PropTypes.object.isRequired, + team: PropTypes.object.isRequired +} + +export default ManageTeamsItem diff --git a/client/src/views/dashboard/components/ManageTeamsList.js b/client/src/views/dashboard/components/ManageTeamsList.js new file mode 100644 index 000000000..b02592c8e --- /dev/null +++ b/client/src/views/dashboard/components/ManageTeamsList.js @@ -0,0 +1,128 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { Query } from 'react-apollo' + +import Typography from '@material-ui/core/Typography' +import Grid from '@material-ui/core/Grid' +import { withStyles } from '@material-ui/core/styles' + +import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery' + +import { isEmpty } from '../../../utils/js-helpers' + +import ManageTeamsItem from './ManageTeamsItem' +import ManageTeamsDetails from './ManageTeamsDetails' + +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: '56.25%' // 16:9 + }, + cardContent: { + flexGrow: 1 + }, + buttonRight: { + justifyContent: 'flex-end' + } +}) + +export const ManageTeamsList = ({ classes, match }) => ( + + {({ loading, error, data }) => { + console.log('GET_TEAMS_BY_OWNER: ', loading, error, data, match) + let slug = null + if (!isEmpty(match.params) && match.params.slug) slug = match.params.slug + + let errors + let queryLoader + if (error) { + errors = error.graphQLErrors.map(({ message }, i) => { + return ( + + {message} + + ) + }) + } + if (!loading && !error) { + if (data.teams.edges.length > 0) { + if (slug !== null) { + return ( + + {!loading && + data.teams.edges.map(team => { + if (team.node.slug === slug) { + return ( + + ) + } + })} + {queryLoader} + {errors} + + ) + } else { + return ( + +
+ + Teams + +
+ + {!loading && + data.teams.edges.map(team => ( + + ))} + {queryLoader} + {errors} + +
+ ) + } + } + } else { + return ( + + + Loading... + + {queryLoader} + {errors} + + ) + } + }} +
+) + +ManageTeamsList.propTypes = { + classes: PropTypes.object.isRequired, + match: PropTypes.object +} + +export default withStyles(styles)(ManageTeamsList) diff --git a/client/src/views/teams/components/TeamsList.js b/client/src/views/teams/components/TeamsList.js index 8ae962ead..64493cdff 100644 --- a/client/src/views/teams/components/TeamsList.js +++ b/client/src/views/teams/components/TeamsList.js @@ -41,7 +41,7 @@ const styles = theme => ({ export const TeamsList = ({ classes, match }) => ( {({ loading, error, data }) => { - console.log('GET_TEAMS_BY_OWNER: ', loading, error, data, match) + console.log('GET_ALL_TEAMS: ', loading, error, data, match) let slug = null if (!isEmpty(match.params) && match.params.slug) slug = match.params.slug From 19f1ea54e45d1684174dc14439ace06b52e8dcca Mon Sep 17 00:00:00 2001 From: Barry Low Date: Fri, 14 Sep 2018 08:43:07 -0700 Subject: [PATCH 10/16] Client Add Manage Actions --- api/src/index.js | 6 +- api/src/schema.graphql | 2 +- .../teams/UpdateTeamProfileMutation.js | 8 +- client/src/views/dashboard/ManageTeams.js | 4 +- .../dashboard/components/ManageTeamsItem.js | 29 ++- .../dashboard/components/ManageTeamsList.js | 167 +++++++++--------- 6 files changed, 105 insertions(+), 111 deletions(-) diff --git a/api/src/index.js b/api/src/index.js index 6b4a5167d..3e0880065 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -101,14 +101,14 @@ const resolvers = { }) }, async updateTeamProfile(parent, { slug, owner, description, motto, avatar }, ctx, info) { - return ctx.db.mutation.updateTeam({data:{profile: {update: {description: description, motto: motto, avatar: avatar}}}, where:{slug: slug}}), TEAMS_FRAGMENT) + return ctx.db.mutation.updateTeam({data:{profile: {update: {description: description, motto: motto, avatar: avatar}}}, where:{slug: slug}}, TEAMS_FRAGMENT) .catch((err) => { console.log('createTeam error: ', err) return err }) }, - async deleteTeam(parent, { id }, ctx, info) { - return ctx.db.mutation.deleteTeam({ where: { id } }, info) + async deleteTeam(parent, { slug }, ctx, info) { + return ctx.db.mutation.deleteTeam({ where: { slug } }, info) .catch((res) => { console.log('deleteTeam error: ', res) const errors = res.graphQLErrors.map((error) => { diff --git a/api/src/schema.graphql b/api/src/schema.graphql index 8b5d48d77..1450c6000 100644 --- a/api/src/schema.graphql +++ b/api/src/schema.graphql @@ -20,7 +20,7 @@ type Mutation { authenticate(idToken: String!): Member createTeam(name: String!, slug: String!, owner: String!): Team @isAuthenticated updateTeamProfile(slug: String!, owner: String!, description: String, motto: String, avatar: String): Team @isAuthenticated - deleteTeam(id: ID!): Team @isAuthenticated @isOwner(type: "Team") + deleteTeam(slug: String!): Team @isAuthenticated @isOwner(type: "Team") } input MemberProfileInput { diff --git a/client/src/graphql/teams/UpdateTeamProfileMutation.js b/client/src/graphql/teams/UpdateTeamProfileMutation.js index 6672a7a24..6da940d4c 100644 --- a/client/src/graphql/teams/UpdateTeamProfileMutation.js +++ b/client/src/graphql/teams/UpdateTeamProfileMutation.js @@ -1,9 +1,9 @@ /* eslint-disable no-unused-vars */ import gql from 'graphql-tag' -const CREATE_TEAM = gql` - mutation UpdateTeamMutation($slug: String!, $owner: String!, $description: String, $motto: String) { - createTeam(slug: $slug, owner: $owner, description: $description, motto: $motto) { +const UPDATE_TEAM_PROFILE = gql` + mutation UpdateTeamProfileMutation($slug: String!, $owner: String!, $description: String, $motto: String) { + updateTeamProfile(slug: $slug, owner: $owner, description: $description, motto: $motto) { id name slug @@ -31,4 +31,4 @@ const CREATE_TEAM = gql` } ` -export default CREATE_TEAM +export default UPDATE_TEAM_PROFILE diff --git a/client/src/views/dashboard/ManageTeams.js b/client/src/views/dashboard/ManageTeams.js index 175c4aded..7eceeb1ca 100644 --- a/client/src/views/dashboard/ManageTeams.js +++ b/client/src/views/dashboard/ManageTeams.js @@ -17,9 +17,7 @@ const ManageTeams = ({ classes }) => ( Manage Your Teams -
- -
+
) diff --git a/client/src/views/dashboard/components/ManageTeamsItem.js b/client/src/views/dashboard/components/ManageTeamsItem.js index 7c00639d9..d765e0ad0 100644 --- a/client/src/views/dashboard/components/ManageTeamsItem.js +++ b/client/src/views/dashboard/components/ManageTeamsItem.js @@ -3,19 +3,16 @@ 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 { Link } from 'react-router-dom' - export const ManageTeamsItem = ({ classes, team }) => ( - + - +
( {team.name} - {team.createdAt} - - - Members: 1 - - - Now recruiting! + {team.createdAt} | Members: {team.members.length} - - - + - - + + + +
) diff --git a/client/src/views/dashboard/components/ManageTeamsList.js b/client/src/views/dashboard/components/ManageTeamsList.js index b02592c8e..c15316e60 100644 --- a/client/src/views/dashboard/components/ManageTeamsList.js +++ b/client/src/views/dashboard/components/ManageTeamsList.js @@ -1,17 +1,18 @@ import React from 'react' import PropTypes from 'prop-types' import { Query } from 'react-apollo' +import { withStateHandlers, lifecycle, compose } from 'recompose' import Typography from '@material-ui/core/Typography' 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 { isEmpty } from '../../../utils/js-helpers' - import ManageTeamsItem from './ManageTeamsItem' -import ManageTeamsDetails from './ManageTeamsDetails' const styles = theme => ({ heroContent: { @@ -22,107 +23,107 @@ const styles = theme => ({ cardGrid: { padding: `${theme.spacing.unit * 8}px 0` }, - card: { - height: '100%', - display: 'flex', - flexDirection: 'column' - }, - cardMedia: { - paddingTop: '56.25%' // 16:9 - }, - cardContent: { - flexGrow: 1 - }, 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, match }) => ( - - {({ loading, error, data }) => { - console.log('GET_TEAMS_BY_OWNER: ', loading, error, data, match) - let slug = null - if (!isEmpty(match.params) && match.params.slug) slug = match.params.slug +export const ManageTeamsList = ({ 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) - let errors - let queryLoader - if (error) { - errors = error.graphQLErrors.map(({ message }, i) => { - return ( - - {message} - - ) - }) - } - if (!loading && !error) { - if (data.teams.edges.length > 0) { - if (slug !== null) { + return ( + + {({ loading, error, data }) => { + console.log('GET_TEAMS_BY_OWNER: ', loading, error, data) + + let errors + if (error) { + errors = error.graphQLErrors.map(({ message }, i) => { return ( - - {!loading && - data.teams.edges.map(team => { - if (team.node.slug === slug) { - return ( - - ) - } - })} - {queryLoader} - {errors} - + + {message} + ) - } else { + }) + } + if (!loading && !error) { + if (data.teamsByOwner.length > 0) { return ( -
- - Teams - -
{!loading && - data.teams.edges.map(team => ( + data.teamsByOwner.map(team => ( ))} - {queryLoader} {errors}
) } + } else { + return ( + + + Loading... + + {errors} + + ) } - } else { - return ( - - - Loading... - - {queryLoader} - {errors} - - ) - } - }} -
-) - -ManageTeamsList.propTypes = { - classes: PropTypes.object.isRequired, - match: PropTypes.object + }} +
+ ) } -export default withStyles(styles)(ManageTeamsList) +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) From a99ab30c03255058e46f1b1807f12de529b979a1 Mon Sep 17 00:00:00 2001 From: Barry Low Date: Fri, 14 Sep 2018 22:52:41 -0700 Subject: [PATCH 11/16] Solidify Dash Panel Queries and Mutations --- api/src/index.js | 2 +- .../src/graphql/teams/DeleteTeamMutation.js | 4 +++- .../views/dashboard/components/CreateTeam.js | 21 ++++++++++++------- .../dashboard/components/CreateTeamWrapper.js | 7 ++++--- .../views/dashboard/components/DashTeam.js | 4 ++-- .../dashboard/components/ManageTeamsItem.js | 6 +++--- 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/api/src/index.js b/api/src/index.js index 3e0880065..8f3670a7a 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -58,7 +58,7 @@ const resolvers = { }, async teamsByOwner(parent, { ownerId }, ctx, info) { console.log('teamsByOwner: ', ctx.user) - return ctx.db.query.teams({where: { owner: ownerId }}, TEAMS_FRAGMENT) + return ctx.db.query.teams({where: { owner: ownerId }, orderBy:'updatedAt_DESC'}, TEAMS_FRAGMENT) }, async owner(parent, args, ctx, info) { console.log('resolver.query.owner ctx: ', ctxMember(ctx)) diff --git a/client/src/graphql/teams/DeleteTeamMutation.js b/client/src/graphql/teams/DeleteTeamMutation.js index 91723348d..998e5c643 100644 --- a/client/src/graphql/teams/DeleteTeamMutation.js +++ b/client/src/graphql/teams/DeleteTeamMutation.js @@ -1,10 +1,12 @@ /* eslint-disable no-unused-vars */ import gql from 'graphql-tag' -export const DeleteTeamMutation = gql` +export const DELETE_TEAM = gql` mutation deleteTeam($id: ID!) { deleteTeam(id: $id) { id } } ` + +export default DELETE_TEAM diff --git a/client/src/views/dashboard/components/CreateTeam.js b/client/src/views/dashboard/components/CreateTeam.js index 90cac23f7..1dfb75850 100644 --- a/client/src/views/dashboard/components/CreateTeam.js +++ b/client/src/views/dashboard/components/CreateTeam.js @@ -1,4 +1,5 @@ import React from 'react' +import PropTypes from 'prop-types' import { Mutation } from 'react-apollo' import Typography from '@material-ui/core/Typography' @@ -9,18 +10,19 @@ import { checkGraphQLError } from '../../../utils/graphql-errors' import CREATE_TEAM from '../../../graphql/teams/CreateTeamMutation' import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery' -const CreateTeam = () => { +const CreateTeam = ({ authId }) => { let input + console.log('CreateTeam', authId) return ( { - const data = cache.readQuery({ query: GET_TEAMS_BY_OWNER }) - console.log('Mutation cache update: ', createTeam, data) - data.getTeamsByOwner.push(createTeam) - cache.writeQuery({ query: GET_TEAMS_BY_OWNER, data }) - }} + refetchQueries={[ + { + query: GET_TEAMS_BY_OWNER, + variables: { authId } + } + ]} > {(createTeam, { loading, error, data }) => { let errors @@ -62,11 +64,16 @@ const CreateTeam = () => { ) } +CreateTeam.propTypes = { + authId: PropTypes.any +} + const handleSubmit = async (e, createTeam, input) => { e.preventDefault() const currentUser = await getItem('user') let authId = JSON.parse(currentUser) authId = authId.authId + console.log('createTeam submit: ', authId) const name = input.value const slug = slugify(name) await createTeam({ variables: { name, slug, owner: authId } }) diff --git a/client/src/views/dashboard/components/CreateTeamWrapper.js b/client/src/views/dashboard/components/CreateTeamWrapper.js index c4a44b312..68750bffc 100644 --- a/client/src/views/dashboard/components/CreateTeamWrapper.js +++ b/client/src/views/dashboard/components/CreateTeamWrapper.js @@ -28,13 +28,13 @@ const styles = theme => ({ } }) -const CreateTeamWrapper = ({ classes }) => ( +const CreateTeamWrapper = ({ classes, authId }) => (
- +
@@ -43,7 +43,8 @@ const CreateTeamWrapper = ({ classes }) => ( ) CreateTeamWrapper.propTypes = { - classes: PropTypes.object.isRequired + classes: PropTypes.object.isRequired, + authId: PropTypes.string } export default withStyles(styles)(CreateTeamWrapper) diff --git a/client/src/views/dashboard/components/DashTeam.js b/client/src/views/dashboard/components/DashTeam.js index d8b2df1ce..cad20bf57 100644 --- a/client/src/views/dashboard/components/DashTeam.js +++ b/client/src/views/dashboard/components/DashTeam.js @@ -27,7 +27,7 @@ export const DashTeam = ({ classes, user = null }) => { } console.log('DashTeam 2: ', owner, authId) - if (authId === null) { + if (authId === undefined || authId === null) { return ( @@ -42,7 +42,7 @@ export const DashTeam = ({ classes, user = null }) => { Teams - + {({ loading, error, data }) => { console.log('GET_TEAMS_BY_OWNER: ', loading, error, data) diff --git a/client/src/views/dashboard/components/ManageTeamsItem.js b/client/src/views/dashboard/components/ManageTeamsItem.js index d765e0ad0..fdb6534f4 100644 --- a/client/src/views/dashboard/components/ManageTeamsItem.js +++ b/client/src/views/dashboard/components/ManageTeamsItem.js @@ -9,6 +9,8 @@ import CardMedia from '@material-ui/core/CardMedia' import Button from '@material-ui/core/Button' import Typography from '@material-ui/core/Typography' +import ManageTeamDelete from './ManageTeamDelete' + export const ManageTeamsItem = ({ classes, team }) => ( @@ -30,9 +32,7 @@ export const ManageTeamsItem = ({ classes, team }) => ( - + From 14702b7f464c4c10dd121b547b9fcab32aa3cffe Mon Sep 17 00:00:00 2001 From: Barry Low Date: Sun, 16 Sep 2018 22:51:14 -0700 Subject: [PATCH 12/16] Client: Manage Team Dialogs --- api/src/auth/authDirectives.js | 16 +- .../src/graphql/teams/DeleteTeamMutation.js | 4 +- client/src/views/common/MessageCard.js | 43 ++++ client/src/views/common/index.js | 3 + client/src/views/dashboard/Overview.js | 7 + .../dashboard/components/CreateTeamDialog.js | 196 +++++++++++++++++ .../views/dashboard/components/DashTeam.js | 19 +- .../dashboard/components/ManageTeamDelete.js | 130 ++++++++++++ .../dashboard/components/ManageTeamEdit.js | 199 ++++++++++-------- .../dashboard/components/ManageTeamsItem.js | 12 +- .../dashboard/components/ManageTeamsList.js | 108 ++++++---- 11 files changed, 593 insertions(+), 144 deletions(-) create mode 100644 client/src/views/common/MessageCard.js create mode 100644 client/src/views/common/index.js create mode 100644 client/src/views/dashboard/components/CreateTeamDialog.js create mode 100644 client/src/views/dashboard/components/ManageTeamDelete.js diff --git a/api/src/auth/authDirectives.js b/api/src/auth/authDirectives.js index 471be4692..0ba153fce 100644 --- a/api/src/auth/authDirectives.js +++ b/api/src/auth/authDirectives.js @@ -71,8 +71,8 @@ const isLoggedIn = async ctx => { const isRequestingMemberAlsoOwner = ({ ctx, memberId, type, typeId }) => - ctx.db.exists[type]({ id: typeId, owner: { auth0id: memberId } }) -const isRequestingMember = ({ ctx, memberId }) => ctx.db.exists.Member({ auth0id: memberId }) + ctx.db.exists[type]({ slug: typeId, owner: memberId }) +const isRequestingMember = ({ ctx, memberId }) => ctx.db.exists.Member({ authId: memberId }) const directiveResolvers = { isAuthenticated: async (next, source, args, ctx) => { @@ -89,12 +89,14 @@ const directiveResolvers = { throw new Error(`Unauthorized, incorrect role`) }, isOwner: async (next, source, { type }, ctx) => { - const { id: typeId } = + console.log('directive isOwner: ', source, type, ctx) + const { slug: typeId } = source && source.id ? source : ctx.request.body.variables ? ctx.request.body.variables : { id: null } - const { auth0id: memberId } = await isLoggedIn(ctx) - console.log('directive isOwner 0: ', type, typeId, memberId) + const user = await isLoggedIn(ctx) + console.log('directive isOwner 0: ', typeId, user.sub) + const memberId = user.sub const isOwner = type === `Member` ? memberId === typeId @@ -106,14 +108,14 @@ const directiveResolvers = { throw new Error(`Unauthorized, must be owner`) }, isOwnerOrHasRole: async (next, source, { roles, type }, ctx, ...p) => { - const { auth0id: memberId } = await isLoggedIn(ctx) + const { authId: memberId } = await isLoggedIn(ctx) console.log('directive isOwnerOrHasRole 1: ', memberId, roles, type) if(memberId === undefined && role=== undefined) throw new Error(`Not logged in`) if (roles.includes(role)) { return next() } - const { auth0id: typeId } = ctx.request.body.variables + const { authId: typeId } = ctx.request.body.variables const isOwner = await isRequestingMemberAlsoOwner({ ctx, memberId, diff --git a/client/src/graphql/teams/DeleteTeamMutation.js b/client/src/graphql/teams/DeleteTeamMutation.js index 998e5c643..8e349c58a 100644 --- a/client/src/graphql/teams/DeleteTeamMutation.js +++ b/client/src/graphql/teams/DeleteTeamMutation.js @@ -2,8 +2,8 @@ import gql from 'graphql-tag' export const DELETE_TEAM = gql` - mutation deleteTeam($id: ID!) { - deleteTeam(id: $id) { + mutation deleteTeam($slug: String!) { + deleteTeam(slug: $slug) { id } } diff --git a/client/src/views/common/MessageCard.js b/client/src/views/common/MessageCard.js new file mode 100644 index 000000000..60668fd62 --- /dev/null +++ b/client/src/views/common/MessageCard.js @@ -0,0 +1,43 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import Typography from '@material-ui/core/Typography' +import { withStyles } from '@material-ui/core/styles' + +import Card from '@material-ui/core/Card' +import CardContent from '@material-ui/core/CardContent' + +const styles = theme => ({ + card: { + display: 'flex', + width: '100%', + margin: '1.5em', + padding: '3em' + }, + cardDetails: { + display: 'flex', + flex: 1 + }, + cardContent: { + flex: 1 + } +}) + +export const MessageCard = ({ classes, message, children }) => ( + +
+ + {message} + {children} + +
+
+) + +MessageCard.propTypes = { + children: PropTypes.node, + classes: PropTypes.object.isRequired, + message: PropTypes.string.isRequired +} + +export default withStyles(styles)(MessageCard) diff --git a/client/src/views/common/index.js b/client/src/views/common/index.js new file mode 100644 index 000000000..fe07e8f49 --- /dev/null +++ b/client/src/views/common/index.js @@ -0,0 +1,3 @@ +import MessageCard from './MessageCard' + +export { MessageCard } diff --git a/client/src/views/dashboard/Overview.js b/client/src/views/dashboard/Overview.js index c79b2eec9..87aa217bf 100644 --- a/client/src/views/dashboard/Overview.js +++ b/client/src/views/dashboard/Overview.js @@ -34,6 +34,13 @@ const styles = theme => ({ aawebMedia: { width: '100%', height: 320 + }, + dashLink: { + float: 'right', + color: '#111', + fontSize: 16, + textDecoration: 'none', + paddingRight: '1em' } }) diff --git a/client/src/views/dashboard/components/CreateTeamDialog.js b/client/src/views/dashboard/components/CreateTeamDialog.js new file mode 100644 index 000000000..66e0f00e5 --- /dev/null +++ b/client/src/views/dashboard/components/CreateTeamDialog.js @@ -0,0 +1,196 @@ +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 DialogContentText from '@material-ui/core/DialogContentText' +import DialogTitle from '@material-ui/core/DialogTitle' +import Typography from '@material-ui/core/Typography' + +import { getItem } from '../../../utils/local-storage' +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 => ({ + dialogStyle: { + padding: '3em' + }, + 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: '', + errors: { + name: '' + } + } + } + + render () { + const { classes, authId } = this.props + return ( + + {(createTeam, { loading, error, data }) => { + let errors + let loader = null + if (loading) { + loader = Submitting team... + } + if (error) { + errors = error.graphQLErrors.map(({ message }, i) => { + // const displayMessage = checkGraphQLError(message) + return ( + + {message} + + ) + }) + } + return ( +
+ + + Create a Team + + Team Name: + (this.state.errors.name !== '' || error)}> + this.state.errors.name !== '' || error} + /> + {this.state.errors.name !== '' && ({this.state.errors.name})} + {error && ({errors})} + {loader} + + + + + + + +
+ ) + }} +
+ ) + } + + 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: { name: '' } }) + this.setState({ name: e.target.value }) + } else { + this.setState({ errors: errors }) + this.setState({ name: e.target.value }) + } + } + + async handleSubmit (e, createTeam, name) { + e.preventDefault() + const currentUser = await getItem('user') + let authId = JSON.parse(currentUser) + authId = authId.authId + console.log('createTeam submit: ', authId, name) + const slug = this.slugify(name) + await createTeam({ variables: { name, slug, owner: authId } }) + this.setState({ name: '' }) + } + + validate (data) { + const errors = {} + if (data === '') errors.name = 'Please enter a team name' + 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) diff --git a/client/src/views/dashboard/components/DashTeam.js b/client/src/views/dashboard/components/DashTeam.js index cad20bf57..8201e9d4d 100644 --- a/client/src/views/dashboard/components/DashTeam.js +++ b/client/src/views/dashboard/components/DashTeam.js @@ -2,6 +2,7 @@ import React from 'react' import PropTypes from 'prop-types' import { Query } from 'react-apollo' import { withStateHandlers, lifecycle, compose } from 'recompose' +import { Link } from 'react-router-dom' import Typography from '@material-ui/core/Typography' import Grid from '@material-ui/core/Grid' @@ -9,7 +10,8 @@ import Grid from '@material-ui/core/Grid' import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery' import DashTeamItem from './DashTeamItem' -import CreateTeamWrapper from './CreateTeamWrapper' +import CreateTeamDialog from './CreateTeamDialog' +import { MessageCard } from '../../common/' import { isDefined, isString } from '../../../utils/js-helpers' import { getItem } from '../../../utils/local-storage' @@ -38,11 +40,10 @@ export const DashTeam = ({ classes, user = null }) => { ) } return ( - + - Teams + Teams Manage Teams - {({ loading, error, data }) => { console.log('GET_TEAMS_BY_OWNER: ', loading, error, data) @@ -70,6 +71,16 @@ export const DashTeam = ({ classes, user = null }) => { {loader} ) + } else { + return ( + + + + + + + + ) } } else { return ( diff --git a/client/src/views/dashboard/components/ManageTeamDelete.js b/client/src/views/dashboard/components/ManageTeamDelete.js new file mode 100644 index 000000000..231dbab14 --- /dev/null +++ b/client/src/views/dashboard/components/ManageTeamDelete.js @@ -0,0 +1,130 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import { withRouter } from 'react-router-dom' +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' + +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, + motto: '', + description: '' + } + } + + 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 authId = this.props.authId + return ( + { + const data = cache.readQuery({ query: GET_TEAMS_BY_OWNER }) + console.log('Mutation cache update: ', deleteTeam, data) + data.getTeamsByOwner.push(deleteTeam) + cache.writeQuery({ query: GET_TEAMS_BY_OWNER, data }) + }} + > + {(deleteTeam, { loading, error, data }) => { + let errors + let loader + if (loading) { + loader = Submitting team... + } + if (error) { + errors = error.graphQLErrors.map(({ message }, i) => { + const displayMessage = checkGraphQLError(message) + console.log('createTeam error:', displayMessage) + return ( + + {message} + + ) + }) + } + return ( +
+ + + Delete Team Team + + DANGER - Deleting your team cannot be undone + Are you sure you want to delete this team? + {loader} + {errors} + + + + + + +
+ ) + }} +
+ ) + } + + async handleSubmit (e, deleteTeam, slug, authId) { + e.preventDefault() + await deleteTeam({ variables: { slug, owner: authId } }) + } +} + +ManageTeamDelete.propTypes = { + classes: PropTypes.object.isRequired, + slug: PropTypes.string.isRequired, + authId: PropTypes.string.isRequired +} + +export default withRouter(ManageTeamDelete) diff --git a/client/src/views/dashboard/components/ManageTeamEdit.js b/client/src/views/dashboard/components/ManageTeamEdit.js index d10dd5728..6937cc7f9 100644 --- a/client/src/views/dashboard/components/ManageTeamEdit.js +++ b/client/src/views/dashboard/components/ManageTeamEdit.js @@ -1,8 +1,10 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import { withRouter } from 'react-router-dom' +import { Mutation } from 'react-apollo' + import Button from '@material-ui/core/Button' -import AddIcon from '@material-ui/icons/Add' +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' @@ -13,15 +15,19 @@ import Typography from '@material-ui/core/Typography' import { getItem } from '../../../utils/local-storage' +import UPDATE_TEAM_PROFILE from '../../../graphql/teams/UpdateTeamProfileMutation' +import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery' + +import { checkGraphQLError } from '../../../utils/graphql-errors' + export class ManageTeamEdit extends Component { constructor (props) { super(props) this.handleClickOpen = this.handleClickOpen.bind(this) this.handleClose = this.handleClose.bind(this) - this.handlePost = this.handlePost.bind(this) - this.slugify = this.slugify.bind(this) this.handleChange = this.handleChange.bind(this) + this.handleSubmit = this.handleSubmit.bind(this) this.state = { open: false, @@ -30,6 +36,101 @@ export class ManageTeamEdit extends Component { } } + render () { + console.log(this.props, this.props.slug) + return ( + { + const data = cache.readQuery({ query: GET_TEAMS_BY_OWNER }) + console.log('Mutation cache update: ', deleteTeam, data) + data.getTeamsByOwner.push(deleteTeam) + cache.writeQuery({ query: GET_TEAMS_BY_OWNER, data }) + }} + > + {(updateTeamProfile, { loading, error, data }) => { + let errors + let loader + let description + let motto + if (loading) { + loader = Submitting team... + } + if (error) { + errors = error.graphQLErrors.map(({ message }, i) => { + const displayMessage = checkGraphQLError(message) + console.log('updateTeamProfile error:', displayMessage) + return ( + + {message} + + ) + }) + } + return ( +
+ + + Edit Team Details + + Team Creation + Team Motto: + { + motto = node + }} + /> + Team description: + { + description = node + }} + /> + {loader} + {errors} + + + + + + +
+ ) + }} +
+ ) + } + handleClickOpen () { this.setState({ open: true }) } @@ -39,95 +140,29 @@ export class ManageTeamEdit extends Component { } handleChange (e) { - this.setState({ name: 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: + } } - render () { - console.log(this.props, this.props.team) - return ( -
- - - Edit Team Details - - Team Creation - Team Motto: - - - - - - - -
- ) - } - - 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 - } - - async handlePost (e) { + async handleSubmit (e, updateTeamProfile, slug, description, motto) { e.preventDefault() - const { name } = this.state - const slug = this.slugify(name) const currentUser = await getItem('user') let authId = JSON.parse(currentUser) - authId = authId.sub - console.log('createPage cu:', JSON.parse(currentUser)) - await this.props.createTeamMutation({ - variables: { - name, - slug, - owner: authId - } - }) - this.setState({ open: false }) + authId = authId.authId + await updateTeamProfile({ variables: { slug, owner: authId, description: description, motto: motto } }) } } ManageTeamEdit.propTypes = { classes: PropTypes.object.isRequired, - team: PropTypes.object.isRequired, - createTeamMutation: PropTypes.function + slug: PropTypes.string.isRequired } export default withRouter(ManageTeamEdit) diff --git a/client/src/views/dashboard/components/ManageTeamsItem.js b/client/src/views/dashboard/components/ManageTeamsItem.js index fdb6534f4..f84fe3d40 100644 --- a/client/src/views/dashboard/components/ManageTeamsItem.js +++ b/client/src/views/dashboard/components/ManageTeamsItem.js @@ -10,8 +10,9 @@ import Button from '@material-ui/core/Button' import Typography from '@material-ui/core/Typography' import ManageTeamDelete from './ManageTeamDelete' +import ManageTeamEdit from './ManageTeamEdit' -export const ManageTeamsItem = ({ classes, team }) => ( +export const ManageTeamsItem = ({ classes, team, authId }) => (
@@ -32,10 +33,8 @@ export const ManageTeamsItem = ({ classes, team }) => ( - - + +
@@ -44,7 +43,8 @@ export const ManageTeamsItem = ({ classes, team }) => ( ManageTeamsItem.propTypes = { classes: PropTypes.object.isRequired, - team: PropTypes.object.isRequired + team: PropTypes.object.isRequired, + authId: PropTypes.string.isRequired } export default ManageTeamsItem diff --git a/client/src/views/dashboard/components/ManageTeamsList.js b/client/src/views/dashboard/components/ManageTeamsList.js index c15316e60..6a6bebde4 100644 --- a/client/src/views/dashboard/components/ManageTeamsList.js +++ b/client/src/views/dashboard/components/ManageTeamsList.js @@ -3,7 +3,6 @@ import PropTypes from 'prop-types' import { Query } from 'react-apollo' import { withStateHandlers, lifecycle, compose } from 'recompose' -import Typography from '@material-ui/core/Typography' import Grid from '@material-ui/core/Grid' import { withStyles } from '@material-ui/core/styles' @@ -13,6 +12,8 @@ import { getItem } from '../../../utils/local-storage' import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery' import ManageTeamsItem from './ManageTeamsItem' +import CreateTeamDialog from './CreateTeamDialog' +import { MessageCard } from '../../common/' const styles = theme => ({ heroContent: { @@ -55,53 +56,74 @@ export const ManageTeamsList = ({ classes, user = null }) => { if (isDefined(owner.authId)) authId = owner.authId } console.log('ManageTeamsList 2: ', owner, authId) + if (authId === undefined || authId === null) { + return ( + + + + + + ) + } else { + return ( + + {({ loading, error, data }) => { + console.log('GET_TEAMS_BY_OWNER: ', loading, error, data) - return ( - - {({ loading, error, data }) => { - console.log('GET_TEAMS_BY_OWNER: ', loading, error, data) - - let errors - if (error) { - errors = error.graphQLErrors.map(({ message }, i) => { - return ( - - {message} - - ) - }) - } - if (!loading && !error) { - if (data.teamsByOwner.length > 0) { - return ( - + let errors = null + if (error) { + errors = error.graphQLErrors.map(({ message }, i) => { + return ( + + ) + }) + } + if (!loading && !error) { + if (data.teamsByOwner.length > 0) { + return ( + + + {!loading && + data.teamsByOwner.map(team => ( + + ))} + + + + {errors} + + + ) + } else { + return ( - {!loading && - data.teamsByOwner.map(team => ( - - ))} - {errors} + + + + + - + ) + } + } else { + return ( + + + + if (errors !== null) () + + ) } - } else { - return ( - - - Loading... - - {errors} - - ) - } - }} - - ) + }} + + ) + } } ManageTeamsList.propTypes = { From 975019b4234790b99494072569a659784057c1c5 Mon Sep 17 00:00:00 2001 From: Barry Low Date: Sun, 16 Sep 2018 23:29:23 -0700 Subject: [PATCH 13/16] Client: Manage Team Edit Details Dialog --- api/database/datamodel.graphql | 1 + api/src/index.js | 2 +- client/src/views/common/MessageCard.js | 2 +- .../dashboard/components/CreateTeamDialog.js | 2 +- .../views/dashboard/components/DashTeam.js | 2 +- .../dashboard/components/ManageTeamEdit.js | 35 ++++++++----------- .../dashboard/components/ManageTeamsList.js | 4 +-- 7 files changed, 21 insertions(+), 27 deletions(-) diff --git a/api/database/datamodel.graphql b/api/database/datamodel.graphql index 7a55f466d..ddc89814c 100644 --- a/api/database/datamodel.graphql +++ b/api/database/datamodel.graphql @@ -42,6 +42,7 @@ type TeamProfile { motto: String avatar: String updatedAt: DateTime! + createdAt: DateTime! } type TeamStatus { diff --git a/api/src/index.js b/api/src/index.js index 8f3670a7a..d640b8682 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -94,7 +94,7 @@ const resolvers = { return member }, async createTeam(parent, { name, slug, owner }, ctx, info) { - return ctx.db.mutation.createTeam({ data: { name: name, slug: slug, owner: owner, members: { create: { member:{ connect:{ authId: owner} }, role: 'OWNER' } } } }, TEAMS_FRAGMENT) + return ctx.db.mutation.createTeam({ data: { name: name, slug: slug, owner: owner, members: { create: { member:{ connect:{ authId: owner} }, role: 'OWNER' } }, profile:{create:{avatar:"a"} } } }, TEAMS_FRAGMENT) .catch((err) => { console.log('createTeam error: ', err) return err diff --git a/client/src/views/common/MessageCard.js b/client/src/views/common/MessageCard.js index 60668fd62..9c45891d0 100644 --- a/client/src/views/common/MessageCard.js +++ b/client/src/views/common/MessageCard.js @@ -37,7 +37,7 @@ export const MessageCard = ({ classes, message, children }) => ( MessageCard.propTypes = { children: PropTypes.node, classes: PropTypes.object.isRequired, - message: PropTypes.string.isRequired + message: PropTypes.string } export default withStyles(styles)(MessageCard) diff --git a/client/src/views/dashboard/components/CreateTeamDialog.js b/client/src/views/dashboard/components/CreateTeamDialog.js index 66e0f00e5..4db5b5638 100644 --- a/client/src/views/dashboard/components/CreateTeamDialog.js +++ b/client/src/views/dashboard/components/CreateTeamDialog.js @@ -109,7 +109,7 @@ export class CreateTeamDialog extends Component { fullWidth value={this.state.name} onChange={this.handleChange} - error={e => this.state.errors.name !== '' || error} + error={this.state.errors.name !== '' || error} /> {this.state.errors.name !== '' && ({this.state.errors.name})} {error && ({errors})} diff --git a/client/src/views/dashboard/components/DashTeam.js b/client/src/views/dashboard/components/DashTeam.js index 8201e9d4d..1213f7eb1 100644 --- a/client/src/views/dashboard/components/DashTeam.js +++ b/client/src/views/dashboard/components/DashTeam.js @@ -74,7 +74,7 @@ export const DashTeam = ({ classes, user = null }) => { } else { return ( - + diff --git a/client/src/views/dashboard/components/ManageTeamEdit.js b/client/src/views/dashboard/components/ManageTeamEdit.js index 6937cc7f9..6fc498144 100644 --- a/client/src/views/dashboard/components/ManageTeamEdit.js +++ b/client/src/views/dashboard/components/ManageTeamEdit.js @@ -38,21 +38,20 @@ export class ManageTeamEdit extends Component { render () { console.log(this.props, this.props.slug) + const { authId } = this.props return ( { - const data = cache.readQuery({ query: GET_TEAMS_BY_OWNER }) - console.log('Mutation cache update: ', deleteTeam, data) - data.getTeamsByOwner.push(deleteTeam) - cache.writeQuery({ query: GET_TEAMS_BY_OWNER, data }) - }} + refetchQueries={[ + { + query: GET_TEAMS_BY_OWNER, + variables: { authId } + } + ]} > {(updateTeamProfile, { loading, error, data }) => { let errors let loader - let description - let motto if (loading) { loader = Submitting team... } @@ -84,21 +83,17 @@ export class ManageTeamEdit extends Component { { - motto = node - }} /> Team description: { - description = node - }} /> {loader} {errors} @@ -118,7 +110,7 @@ export class ManageTeamEdit extends Component { Cancel @@ -151,18 +143,19 @@ export class ManageTeamEdit extends Component { } } - async handleSubmit (e, updateTeamProfile, slug, description, motto) { + async handleSubmit (e, updateTeamProfile, slug) { e.preventDefault() const currentUser = await getItem('user') let authId = JSON.parse(currentUser) authId = authId.authId - await updateTeamProfile({ variables: { slug, owner: authId, description: description, motto: motto } }) + await updateTeamProfile({ variables: { slug, owner: authId, description: this.state.description, motto: this.state.motto } }) } } ManageTeamEdit.propTypes = { classes: PropTypes.object.isRequired, - slug: PropTypes.string.isRequired + slug: PropTypes.string.isRequired, + authId: PropTypes.string } export default withRouter(ManageTeamEdit) diff --git a/client/src/views/dashboard/components/ManageTeamsList.js b/client/src/views/dashboard/components/ManageTeamsList.js index 6a6bebde4..5a5349e86 100644 --- a/client/src/views/dashboard/components/ManageTeamsList.js +++ b/client/src/views/dashboard/components/ManageTeamsList.js @@ -102,7 +102,7 @@ export const ManageTeamsList = ({ classes, user = null }) => { } else { return ( - + @@ -113,7 +113,7 @@ export const ManageTeamsList = ({ classes, user = null }) => { } else { return ( - + if (errors !== null) () From 16162016d5c96caaec827168bf390739cd604b63 Mon Sep 17 00:00:00 2001 From: Barry Low Date: Sun, 16 Sep 2018 23:50:19 -0700 Subject: [PATCH 14/16] Client: Manage Team Details Dialog --- .../dashboard/components/ManageTeamDetails.js | 94 +++++++++++++++++++ .../dashboard/components/ManageTeamEdit.js | 11 ++- .../components/ManageTeamsDetails.js | 89 ------------------ .../dashboard/components/ManageTeamsItem.js | 8 +- 4 files changed, 104 insertions(+), 98 deletions(-) create mode 100644 client/src/views/dashboard/components/ManageTeamDetails.js delete mode 100644 client/src/views/dashboard/components/ManageTeamsDetails.js diff --git a/client/src/views/dashboard/components/ManageTeamDetails.js b/client/src/views/dashboard/components/ManageTeamDetails.js new file mode 100644 index 000000000..b9420b564 --- /dev/null +++ b/client/src/views/dashboard/components/ManageTeamDetails.js @@ -0,0 +1,94 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' + +import Button from '@material-ui/core/Button' +import DetailsIcon from '@material-ui/icons/Details' +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' + +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 { name, members, profile, createdAt } = this.props.team + return ( +
+ + + {name} Team Details + + + {name} + + + {createdAt} + + + Motto: {profile.motto} + + + Description: {profile.description} + + + Members: {members.length} + + + Team Admin: + { + members.map(member => { + if (member.role === 'OWNER' || member.role === 'ADMIN') { + return member.member.alias + } + }) + } + + + + + + +
+ ) + } + + handleClickOpen () { + this.setState({ open: true }) + } + + handleClose () { + this.setState({ open: false }) + } +} + +ManageTeamDetails.propTypes = { + classes: PropTypes.object.isRequired, + team: PropTypes.any +} + +export default ManageTeamDetails diff --git a/client/src/views/dashboard/components/ManageTeamEdit.js b/client/src/views/dashboard/components/ManageTeamEdit.js index 6fc498144..92def9d44 100644 --- a/client/src/views/dashboard/components/ManageTeamEdit.js +++ b/client/src/views/dashboard/components/ManageTeamEdit.js @@ -28,11 +28,13 @@ export class ManageTeamEdit extends Component { this.handleClose = this.handleClose.bind(this) this.handleChange = this.handleChange.bind(this) this.handleSubmit = this.handleSubmit.bind(this) - + console.log('ManageTeamEdit', props.team) + const motto = props.team.profile.motto + const description = props.team.profile.description this.state = { open: false, - motto: '', - description: '' + motto: motto, + description: description } } @@ -155,7 +157,8 @@ export class ManageTeamEdit extends Component { ManageTeamEdit.propTypes = { classes: PropTypes.object.isRequired, slug: PropTypes.string.isRequired, - authId: PropTypes.string + authId: PropTypes.string, + team: PropTypes.object } export default withRouter(ManageTeamEdit) diff --git a/client/src/views/dashboard/components/ManageTeamsDetails.js b/client/src/views/dashboard/components/ManageTeamsDetails.js deleted file mode 100644 index 65a988215..000000000 --- a/client/src/views/dashboard/components/ManageTeamsDetails.js +++ /dev/null @@ -1,89 +0,0 @@ -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 { withStyles } from '@material-ui/core/styles' - -import { Link } from 'react-router-dom' - -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(900 + theme.spacing.unit * 3 * 2)]: { - width: 900, - marginLeft: 'auto', - marginRight: 'auto' - } - }, - paper: { - marginTop: theme.spacing.unit * 3, - marginBottom: theme.spacing.unit * 3, - padding: theme.spacing.unit * 2, - [theme.breakpoints.up(600 + theme.spacing.unit * 3 * 2)]: { - marginTop: theme.spacing.unit * 6, - marginBottom: theme.spacing.unit * 6, - padding: theme.spacing.unit * 3 - } - }, - heroContent: { - maxWidth: 600, - margin: '0 auto', - padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px` - } -}) - -const ManageTeamsDetails = ({ classes, team }) => ( - - -
- -
- ← Back to all teams - - {team.name} - - - {team.createdAt} - - - Members: {team.members.length} - - - Team Admin: - { - team.members.map(member => { - if (member.role === 'OWNER' || member.role === 'ADMIN') { - return member.member.alias - } - }) - } - -
-
-
-
-) -ManageTeamsDetails.propTypes = { - classes: PropTypes.object.isRequired, - team: PropTypes.object.isRequired -} - -export default withStyles(styles)(ManageTeamsDetails) diff --git a/client/src/views/dashboard/components/ManageTeamsItem.js b/client/src/views/dashboard/components/ManageTeamsItem.js index f84fe3d40..8552bfaf5 100644 --- a/client/src/views/dashboard/components/ManageTeamsItem.js +++ b/client/src/views/dashboard/components/ManageTeamsItem.js @@ -6,9 +6,9 @@ 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 Button from '@material-ui/core/Button' import Typography from '@material-ui/core/Typography' +import ManageTeamDetails from './ManageTeamDetails' import ManageTeamDelete from './ManageTeamDelete' import ManageTeamEdit from './ManageTeamEdit' @@ -30,10 +30,8 @@ export const ManageTeamsItem = ({ classes, team, authId }) => (
- - + +
From b2526b2f3428c41856c210c063cc1ef305d87523 Mon Sep 17 00:00:00 2001 From: Barry Low Date: Mon, 17 Sep 2018 08:14:58 -0700 Subject: [PATCH 15/16] Client: Component style cleanup --- client/src/App.js | 2 + client/src/views/about/index.js | 61 ++++++++++ client/src/views/dashboard/TeamMembers.js | 4 +- .../dashboard/components/DashTeamItem.js | 3 - .../views/dashboard/components/DrawerLinks.js | 6 +- .../dashboard/components/ManageTeamDelete.js | 55 +++++---- .../dashboard/components/ManageTeamDetails.js | 92 +++++++++------ .../dashboard/components/ManageTeamEdit.js | 111 +++++++++++------- .../dashboard/components/ManageTeamsItem.js | 6 +- client/src/views/dashboard/settings.js | 4 +- client/src/views/footer/index.js | 16 +-- client/src/views/index.js | 3 +- 12 files changed, 238 insertions(+), 125 deletions(-) create mode 100644 client/src/views/about/index.js diff --git a/client/src/App.js b/client/src/App.js index 241fa8d1b..652531151 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -20,6 +20,7 @@ import { Footer, Callback, Home, + About, Dashboard, Teams, theme, @@ -149,6 +150,7 @@ class App extends Component { + ({ + '@global': { + body: { + backgroundColor: theme.palette.common.white + } + }, + layout: { + width: 'auto', + marginLeft: theme.spacing.unit * 3, + marginRight: theme.spacing.unit * 3, + [theme.breakpoints.up(900 + theme.spacing.unit * 3 * 2)]: { + width: 900, + marginLeft: 'auto', + marginRight: 'auto' + } + }, + heroContent: { + maxWidth: 600, + margin: '0 auto', + padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px` + } +}) + +const About = ({ classes }) => ( + + +
+
+ + Collaborate. Innovate. Evolve. + + + Welcome to the Advanced Algos Teams Module + +
+
+
+) + +About.propTypes = { + classes: PropTypes.object.isRequired +} + +export default withStyles(styles)(About) diff --git a/client/src/views/dashboard/TeamMembers.js b/client/src/views/dashboard/TeamMembers.js index a22de3714..8b2b43aeb 100644 --- a/client/src/views/dashboard/TeamMembers.js +++ b/client/src/views/dashboard/TeamMembers.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types' import Typography from '@material-ui/core/Typography' import { withStyles } from '@material-ui/core/styles' -import { TeamTable } from './components/TeamTable' +import { MessageCard } from '../common/' const styles = theme => ({ tableContainer: { @@ -18,7 +18,7 @@ const TeamMembers = ({ classes }) => ( Members
- +
) diff --git a/client/src/views/dashboard/components/DashTeamItem.js b/client/src/views/dashboard/components/DashTeamItem.js index 1de33a7a4..b5210e73c 100644 --- a/client/src/views/dashboard/components/DashTeamItem.js +++ b/client/src/views/dashboard/components/DashTeamItem.js @@ -51,9 +51,6 @@ export const DashTeamItem = ({ classes, team }) => ( Members:6 - - Now recruiting! - - Delete Team Team - - DANGER - Deleting your team cannot be undone - Are you sure you want to delete this team? - {loader} - {errors} - - - - - +
+ Delete Team Team + + DANGER - Deleting your team cannot be undone + Are you sure you want to delete this team? + {loader} + {errors} + + + + + +
) @@ -127,4 +140,4 @@ ManageTeamDelete.propTypes = { authId: PropTypes.string.isRequired } -export default withRouter(ManageTeamDelete) +export default withStyles(styles)(ManageTeamDelete) diff --git a/client/src/views/dashboard/components/ManageTeamDetails.js b/client/src/views/dashboard/components/ManageTeamDetails.js index b9420b564..183db0ea8 100644 --- a/client/src/views/dashboard/components/ManageTeamDetails.js +++ b/client/src/views/dashboard/components/ManageTeamDetails.js @@ -1,5 +1,6 @@ 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' @@ -9,6 +10,17 @@ import DialogContent from '@material-ui/core/DialogContent' import DialogTitle from '@material-ui/core/DialogTitle' import Typography from '@material-ui/core/Typography' +const styles = theme => ({ + dialogContainer: { + display: 'block', + margin: '3em', + minWidth: 400 + }, + buttonRight: { + justifyContent: 'flex-end' + } +}) + export class ManageTeamDetails extends Component { constructor (props) { super(props) @@ -34,44 +46,46 @@ export class ManageTeamDetails extends Component { onClose={this.handleClose} aria-labelledby='form-dialog-title' > - {name} Team Details - - - {name} - - - {createdAt} - - - Motto: {profile.motto} - - - Description: {profile.description} - - - Members: {members.length} - - - Team Admin: - { - members.map(member => { - if (member.role === 'OWNER' || member.role === 'ADMIN') { - return member.member.alias - } - }) - } - - - - - +
+ {name} Team Details + + + {name} + + + {createdAt} + + + Motto: {profile.motto} + + + Description: {profile.description} + + + Members: {members.length} + + + Team Admin: + { + members.map(member => { + if (member.role === 'OWNER' || member.role === 'ADMIN') { + return member.member.alias + } + }) + } + + + + + +
) @@ -91,4 +105,4 @@ ManageTeamDetails.propTypes = { team: PropTypes.any } -export default ManageTeamDetails +export default withStyles(styles)(ManageTeamDetails) diff --git a/client/src/views/dashboard/components/ManageTeamEdit.js b/client/src/views/dashboard/components/ManageTeamEdit.js index 92def9d44..7db8b46be 100644 --- a/client/src/views/dashboard/components/ManageTeamEdit.js +++ b/client/src/views/dashboard/components/ManageTeamEdit.js @@ -1,7 +1,7 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' -import { withRouter } from 'react-router-dom' 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' @@ -20,6 +20,17 @@ 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) @@ -29,8 +40,8 @@ export class ManageTeamEdit extends Component { this.handleChange = this.handleChange.bind(this) this.handleSubmit = this.handleSubmit.bind(this) console.log('ManageTeamEdit', props.team) - const motto = props.team.profile.motto - const description = props.team.profile.description + const motto = props.team.profile.motto || '' + const description = props.team.profile.description || '' this.state = { open: false, motto: motto, @@ -40,7 +51,7 @@ export class ManageTeamEdit extends Component { render () { console.log(this.props, this.props.slug) - const { authId } = this.props + const { classes, team, authId } = this.props return ( - - Edit Team Details - - Team Creation - Team Motto: - - Team description: - - {loader} - {errors} - - - - - +
+ Edit Team Details + + + + Team description: + + {loader} + {errors} + + + + + +
) @@ -161,4 +182,4 @@ ManageTeamEdit.propTypes = { team: PropTypes.object } -export default withRouter(ManageTeamEdit) +export default withStyles(styles)(ManageTeamEdit) diff --git a/client/src/views/dashboard/components/ManageTeamsItem.js b/client/src/views/dashboard/components/ManageTeamsItem.js index 8552bfaf5..378dde27e 100644 --- a/client/src/views/dashboard/components/ManageTeamsItem.js +++ b/client/src/views/dashboard/components/ManageTeamsItem.js @@ -30,9 +30,9 @@ export const ManageTeamsItem = ({ classes, team, authId }) => ( - - - + + + diff --git a/client/src/views/dashboard/settings.js b/client/src/views/dashboard/settings.js index a9ee58b58..d28df4d79 100644 --- a/client/src/views/dashboard/settings.js +++ b/client/src/views/dashboard/settings.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types' import Typography from '@material-ui/core/Typography' import { withStyles } from '@material-ui/core/styles' -import { TeamTable } from './components/TeamTable' +import { MessageCard } from '../common/' const styles = theme => ({ tableContainer: { @@ -18,7 +18,7 @@ export const Settings = ({ classes }) => ( Settings
- +
) diff --git a/client/src/views/footer/index.js b/client/src/views/footer/index.js index a7abff6b7..ecbd0c594 100644 --- a/client/src/views/footer/index.js +++ b/client/src/views/footer/index.js @@ -55,26 +55,28 @@ const Footer = ({ classes }) => { Home - + Teams - + About - - Support - - +
+ + Support + + + Documentation - + Telegram diff --git a/client/src/views/index.js b/client/src/views/index.js index 6759b33df..8ff455e85 100644 --- a/client/src/views/index.js +++ b/client/src/views/index.js @@ -2,9 +2,10 @@ import NavBar from './navbar' import Footer from './footer' import Callback from './callback' import Home from './home' +import About from './about' import Dashboard from './dashboard' import Teams from './teams' import { theme, globalStyles } from './theme' -export { NavBar, Footer, Callback, Home, Dashboard, Teams, theme, globalStyles } +export { NavBar, Footer, Callback, Home, About, Dashboard, Teams, theme, globalStyles } From 7bf0c910037b6f7cc3b05a72f7100e90e2758fc7 Mon Sep 17 00:00:00 2001 From: Barry Low Date: Mon, 17 Sep 2018 08:30:59 -0700 Subject: [PATCH 16/16] Client: style navbar --- .../logos/advanced-algos/aa-logo-dark.svg | 1 + client/src/views/navbar/index.js | 18 +++++++++++++++--- client/src/views/theme.js | 4 ++-- 3 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 client/src/assets/logos/advanced-algos/aa-logo-dark.svg diff --git a/client/src/assets/logos/advanced-algos/aa-logo-dark.svg b/client/src/assets/logos/advanced-algos/aa-logo-dark.svg new file mode 100644 index 000000000..479feeb86 --- /dev/null +++ b/client/src/assets/logos/advanced-algos/aa-logo-dark.svg @@ -0,0 +1 @@ +aa-logo-dark \ No newline at end of file diff --git a/client/src/views/navbar/index.js b/client/src/views/navbar/index.js index 34fd52f5f..ca33893d2 100644 --- a/client/src/views/navbar/index.js +++ b/client/src/views/navbar/index.js @@ -20,6 +20,8 @@ import { getItem } from '../../utils/local-storage' import { LoggedIn } from './LoggedIn' import { LoggedOut } from './LoggedOut' +import AALogo from '../../assets/logos/advanced-algos/aa-logo-dark.svg' + const AboutLink = props => const TeamsLink = props => const DashboardLink = props => @@ -34,6 +36,9 @@ const styles = theme => ({ root: { flexGrow: 1 }, + colorDefault: { + color: '#000' + }, flex: { flexGrow: 1 }, @@ -46,6 +51,12 @@ const styles = theme => ({ }, appBar: { position: 'relative' + }, + img: { + margin: 20, + display: 'block', + maxWidth: 240, + maxHeight: 48 } }) @@ -71,8 +82,9 @@ class NavBar extends Component { return (
- + + Advanced Algos - - + + {this.state.user !== undefined && this.state.user !== null ? ( diff --git a/client/src/views/theme.js b/client/src/views/theme.js index 4a2e00ee8..26043dfc0 100644 --- a/client/src/views/theme.js +++ b/client/src/views/theme.js @@ -1,10 +1,10 @@ import { createMuiTheme } from '@material-ui/core/styles' import indigo from '@material-ui/core/colors/indigo' -import red from '@material-ui/core/colors/red' +// import red from '@material-ui/core/colors/red' export const theme = createMuiTheme({ palette: { - primary: red, + primary: { main: '#303036' }, secondary: indigo }, typography: {