diff --git a/frontend-react/package-lock.json b/frontend-react/package-lock.json index 9f2a7ceb4..8026f6b20 100644 --- a/frontend-react/package-lock.json +++ b/frontend-react/package-lock.json @@ -1207,9 +1207,9 @@ "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==" }, "@hapi/hoek": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.0.tgz", - "integrity": "sha512-7XYT10CZfPsH7j9F1Jmg1+d0ezOux2oM2GfArAzLwWe4mE2Dr3hVjsAL6+TFY49RRJlCdJDMw3nJsLFroTc8Kw==" + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.1.tgz", + "integrity": "sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow==" }, "@hapi/joi": { "version": "15.1.1", @@ -1969,9 +1969,9 @@ } }, "@types/history": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.4.tgz", - "integrity": "sha512-+o2igcuZA3xtOoFH56s+MCZVidwlJNcJID57DSCyawS2i910yG9vkwehCjJNZ6ImhCR5S9DbvIJKyYHcMyOfMw==" + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.5.tgz", + "integrity": "sha512-wLD/Aq2VggCJXSjxEwrMafIP51Z+13H78nXIX0ABEuIGhmB5sNGbR113MOKo+yfw+RDo1ZU3DM6yfnnRF/+ouw==" }, "@types/istanbul-lib-coverage": { "version": "2.0.1", @@ -2112,9 +2112,9 @@ "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" }, "@types/node": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.0.tgz", - "integrity": "sha512-GnZbirvmqZUzMgkFn70c74OQpTTUcCzlhQliTzYjQMqg+hVKcDnxdL19Ne3UdYzdMA/+W3eb646FWn/ZaT1NfQ==" + "version": "13.7.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.1.tgz", + "integrity": "sha512-Zq8gcQGmn4txQEJeiXo/KiLpon8TzAl0kmKH4zdWctPj05nWwp1ClMdAVEloqrQKfaC48PNLdgN/aVaLqUrluA==" }, "@types/parse-json": { "version": "4.0.0", @@ -2132,9 +2132,9 @@ "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==" }, "@types/reach__router": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@types/reach__router/-/reach__router-1.2.6.tgz", - "integrity": "sha512-Oh5DAVr/L2svBvubw6QEFpXGu295Y406BPs4i9t1n2pp7M+q3pmCmhzb9oZV5wncR41KCD3NHl1Yhi7uKnTPsA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@types/reach__router/-/reach__router-1.3.0.tgz", + "integrity": "sha512-0aL79bFPJzJOJOOMZm2301ErQVaveBdpW88uuavXymUlcYIAOCmI1ujJ2XLH6Mzn76O94eQCHIl1FDzNNKJCYA==", "requires": { "@types/history": "*", "@types/react": "*" @@ -11786,9 +11786,9 @@ } }, "react-datepicker": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-2.12.0.tgz", - "integrity": "sha512-LlFK36MyQXLSMGB+DiZvPmVw+P1IeCvn2eX3bU1P32T6i8o7+b8LrUVYV9o7slXZMhqOjgTq2vYiXvdRpN/dlQ==", + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-2.12.1.tgz", + "integrity": "sha512-Y5xIim/tzHZ0M+bo6EAZZX5KZ7ov+N6VceSM981bS9dNDoD+ezUAT1/DpeSRXxmFBrNnd5dW4BhlgE36ZzkfLQ==", "requires": { "classnames": "^2.2.6", "date-fns": "^2.0.1", diff --git a/frontend-react/package.json b/frontend-react/package.json index e5279376c..b3b03a4d8 100644 --- a/frontend-react/package.json +++ b/frontend-react/package.json @@ -13,8 +13,8 @@ "@testing-library/react": "^9.4.0", "@testing-library/user-event": "^8.1.0", "@types/jest": "^25.1.2", - "@types/node": "^13.7.0", - "@types/reach__router": "^1.2.6", + "@types/node": "^13.7.1", + "@types/reach__router": "^1.3.0", "@types/react": "^16.9.19", "@types/react-datepicker": "^2.11.0", "@types/react-dom": "^16.9.5", @@ -26,7 +26,7 @@ "jstz": "^2.1.1", "node-sass": "^4.13.1", "react": "^16.12.0", - "react-datepicker": "^2.12.0", + "react-datepicker": "^2.12.1", "react-dom": "^16.12.0", "react-draggable": "^4.2.0", "react-helmet-async": "^1.0.4", diff --git a/frontend-react/src/components/elements/DatePicker.tsx b/frontend-react/src/components/elements/DatePicker.tsx index 797a9da87..88facded4 100644 --- a/frontend-react/src/components/elements/DatePicker.tsx +++ b/frontend-react/src/components/elements/DatePicker.tsx @@ -1,4 +1,4 @@ -import React from "react" +import React, { forwardRef } from "react" import HackerOneDatePicker from "react-datepicker" import Button from "./Button" import "react-datepicker/src/stylesheets/datepicker.scss" @@ -13,15 +13,20 @@ interface CustomInputProps { onClick?: () => void } -const CustomInput: React.FC = ({ value, onClick }) => ( - -) - const DatePicker: React.FC = ({ date, setDate }) => { + const CustomInput: React.FC = forwardRef( + ({ onClick, value }, ref) => ( + + ) + ) + return ( setDate(date)} + onChange={date => { + date?.setUTCHours(0, 0, 0, 0) + setDate(date) + }} customInput={} /> ) diff --git a/frontend-react/src/components/team/AddResultModal.tsx b/frontend-react/src/components/team/AddResultModal.tsx index fa21036ec..1d55680bf 100644 --- a/frontend-react/src/components/team/AddResultModal.tsx +++ b/frontend-react/src/components/team/AddResultModal.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react" +import React, { useState, useEffect } from "react" import Modal from "../elements/Modal" import Box from "../elements/Box" import { TournamentResult } from "../../types" @@ -7,22 +7,27 @@ import { useMutation } from "@apollo/react-hooks" import { useToast } from "@chakra-ui/core" import { ADD_RESULT } from "../../graphql/mutations/addResult" import TweetEmbed from "react-tweet-embed" -import { useContext } from "react" -import MyThemeContext from "../../themeContext" import DatePicker from "../elements/DatePicker" import Label from "../elements/Label" +import PlacementInput from "./PlacementInput" +import Button from "../elements/Button" interface AddResultModalProps { closeModal: () => void } const AddResultModal: React.FC = ({ closeModal }) => { - const { colorMode } = useContext(MyThemeContext) - const [result, setResult] = useState>({}) + const [result, setResult] = useState>({ + placement: 1, + date: (new Date() as unknown) as string, + }) const toast = useToast() const [addResult] = useMutation(ADD_RESULT, { - variables: result as TournamentResult, + variables: { + ...(result as TournamentResult), + date: result.date?.toString() as string, + }, onCompleted: () => { closeModal() toast({ @@ -37,15 +42,30 @@ const AddResultModal: React.FC = ({ closeModal }) => { title: "An error occurred", description: error.message, position: "top-right", - status: "success", + status: "error", duration: 10000, }) }, - refetchQueries: ["searchForUser"], + refetchQueries: ["searchForTeam"], }) + const [error, setError] = useState(null) + + useEffect(() => { + if (!result.tournament_name) { + setError("Tournament name is a required field") + } else if (result.tournament_name.length > 100) { + setError("Tournament name has to be 100 or less characters") + } else if (result.tweet_id && isNaN(result.tweet_id as any)) { + setError("Invalid Tweet ID") + } else if (result.placement && result.placement > 500) { + setError("Placement has to be between 1 and 500.") + } else { + setError(null) + } + }, [result]) + const handleChange = (newValueObject: Partial) => { - console.log("newV", newValueObject) setResult({ ...result, ...newValueObject }) } @@ -83,6 +103,27 @@ const AddResultModal: React.FC = ({ closeModal }) => { )} + + handleChange({ placement: value })} + /> + + + + + + + + {error && ( + + {error} + + )} ) } diff --git a/frontend-react/src/components/team/PlacementInput.tsx b/frontend-react/src/components/team/PlacementInput.tsx new file mode 100644 index 000000000..3fa9a072e --- /dev/null +++ b/frontend-react/src/components/team/PlacementInput.tsx @@ -0,0 +1,33 @@ +import React, { useContext } from "react" +import Label from "../elements/Label" +import { + NumberInput, + NumberInputField, + NumberInputStepper, + NumberIncrementStepper, + NumberDecrementStepper, +} from "@chakra-ui/core" +import MyThemeContext from "../../themeContext" + +interface PlacementInputProps { + value?: number + onChange: (value: number) => void +} + +const PlacementInput: React.FC = ({ value, onChange }) => { + const { themeColorHex } = useContext(MyThemeContext) + return ( + <> + + + + + + + + + + ) +} + +export default PlacementInput diff --git a/frontend-react/src/components/user/BuildFormModal.tsx b/frontend-react/src/components/user/BuildFormModal.tsx index cae78fff6..c2339efe9 100644 --- a/frontend-react/src/components/user/BuildFormModal.tsx +++ b/frontend-react/src/components/user/BuildFormModal.tsx @@ -128,7 +128,7 @@ const BuildFormModal: React.FC = ({ title: "An error occurred", description: error.message, position: "top-right", - status: "success", + status: "error", duration: 10000, }) }, diff --git a/frontend-react/src/components/user/ProfileModal.tsx b/frontend-react/src/components/user/ProfileModal.tsx index 10551353d..b79f35058 100644 --- a/frontend-react/src/components/user/ProfileModal.tsx +++ b/frontend-react/src/components/user/ProfileModal.tsx @@ -79,7 +79,7 @@ const ProfileModal: React.FC = ({ title: "An error occurred", description: error.message, position: "top-right", - status: "success", + status: "error", duration: 10000, }) }, diff --git a/frontend-react/src/graphql/mutations/addResult.ts b/frontend-react/src/graphql/mutations/addResult.ts index a5f0a49de..e9e296a47 100644 --- a/frontend-react/src/graphql/mutations/addResult.ts +++ b/frontend-react/src/graphql/mutations/addResult.ts @@ -7,7 +7,7 @@ export const ADD_RESULT: DocumentNode = gql` $tournament_name: String! $placement: Int! ) { - updateUser( + addResult( date: $date tweet_id: $tweet_id tournament_name: $tournament_name diff --git a/graphql-schemas/team.js b/graphql-schemas/team.js index ccc375786..2b4b11237 100644 --- a/graphql-schemas/team.js +++ b/graphql-schemas/team.js @@ -87,12 +87,11 @@ const resolvers = { throw new UserInputError("Must be logged in") } - if (user.team.captain_discord_id !== user.discord_id) { - //?? - throw new UserInputError("Must be a captain to add a result") - } + const team = await Team.findById(user.team) - if (user.team.tournament_results.length >= 100) { + if (!team) throw new UserInputError("Not a team captain") + + if (team.tournament_results.length > 100) { throw new UserInputError("Can't have more than 100 tournament results") } @@ -100,7 +99,7 @@ const resolvers = { throw new UserInputError("Invalid date") } - if (args.tweet_id && !isNaN(args.tweet_id)) { + if (args.tweet_id && isNaN(args.tweet_id)) { throw new UserInputError("Tweet ID can only contain numbers") } @@ -117,8 +116,7 @@ const resolvers = { throw new UserInputError("Placement has to be between 1 and 500") } - const team = await Team.findById(user.team) - team.push({ + team.tournament_results.push({ date: args.date, tournament_name: args.tournament_name, placement: args.placement, diff --git a/graphql-schemas/user.js b/graphql-schemas/user.js index c40df402b..ad7f6fe06 100644 --- a/graphql-schemas/user.js +++ b/graphql-schemas/user.js @@ -80,6 +80,7 @@ const resolvers = { if (process.env.LOGGED_IN) { return { id: "5cee8f73d1120d4315c55011", + team: "5e3ecc0ea7dd3830303eaaa7", discord_id: "79237403620945920", __v: 0, avatar: "2e292c1b5d1366c24a9e4b6c1cffc700", diff --git a/index.js b/index.js index 6d612630a..3ea565ab3 100644 --- a/index.js +++ b/index.js @@ -91,6 +91,7 @@ const server = new ApolloServer({ return { user: { _id: "5cee8f73d1120d4315c55011", + team: "5e3ecc0ea7dd3830303eaaa7", discord_id: "79237403620945920", __v: 0, avatar: "2e292c1b5d1366c24a9e4b6c1cffc700", diff --git a/package-lock.json b/package-lock.json index c8ad23152..fef9e8477 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1656,9 +1656,9 @@ } }, "mongoose": { - "version": "5.8.11", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.8.11.tgz", - "integrity": "sha512-Yz0leNEJsAtNtMTxTDEadacLWt58gaVeBVL3c1Z3vaBoc159aJqlf+T8jaL9mAdBxKndF5YWhh6Q719xac7cjA==", + "version": "5.8.12", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.8.12.tgz", + "integrity": "sha512-PM6Ks4kIcsLiHcqskVaLj5vDE9l2PoW5foecIuUb5vIG22Gf2yCps31+U3I7Rw8UPnrnbmZvvrRgkHmZR2/Kbw==", "requires": { "bson": "~1.1.1", "kareem": "2.3.1", diff --git a/package.json b/package.json index b0712c4f9..cf3d07e2b 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "express-session": "^1.17.0", "graphql": "^14.6.0", "lodash": "^4.17.15", - "mongoose": "^5.8.11", + "mongoose": "^5.8.12", "mongoose-unique-validator": "^2.0.3", "node-fetch": "^2.6.0", "passport": "^0.4.1",