fapost create update delete

This commit is contained in:
Sendou
2020-03-11 20:27:48 +02:00
parent 9cbb20fb56
commit 5de800a5e3
13 changed files with 387 additions and 71 deletions

View File

@@ -50,7 +50,7 @@ const Modal: React.FC<ModalProps> = ({ children, title, closeModal }) => {
alignItems="center"
fontSize="24px"
fontWeight="black"
mb="1.5em"
mb="0.5em"
>
{title}
{closeModal && (

View File

@@ -10,6 +10,7 @@ interface TextAreaProps {
label?: string
limit?: number
required?: boolean
height?: string
id?: string
}
@@ -19,6 +20,7 @@ const TextArea: React.FC<TextAreaProps> = ({
label,
limit,
required,
height,
}) => {
const { themeColorHex, grayWithShade, darkerBgColor } = useContext(
MyThemeContext
@@ -35,6 +37,7 @@ const TextArea: React.FC<TextAreaProps> = ({
onChange={handleChange}
focusBorderColor={themeColorHex}
size="md"
height={height}
_hover={{}}
background={darkerBgColor}
borderColor="#CCCCCC"

View File

@@ -0,0 +1,324 @@
import React, { useState, useContext } from "react"
import Modal from "../elements/Modal"
import { useMutation } from "@apollo/react-hooks"
import {
useToast,
FormControl,
FormLabel,
RadioGroup,
Radio,
Flex,
Box,
FormErrorMessage,
CheckboxGroup,
Checkbox,
} from "@chakra-ui/core"
import MyThemeContext from "../../themeContext"
import TextArea from "../elements/TextArea"
import Button from "../elements/Button"
import { FreeAgentPost } from "../../types"
import {
AddFreeAgentPostVars,
ADD_FREE_AGENT_POST,
} from "../../graphql/mutations/addFreeAgentPost"
import { FREE_AGENT_POSTS } from "../../graphql/queries/freeAgentPosts"
import { UPDATE_FREE_AGENT_POST } from "../../graphql/mutations/updateFreeAgentPost"
import { HIDE_FREE_AGENT_POST } from "../../graphql/mutations/hideFreeAgentPost"
import Alert from "../elements/Alert"
interface FAPostModalProps {
closeModal: () => void
post?: FreeAgentPost
}
const FAPostModal: React.FC<FAPostModalProps> = ({ closeModal, post }) => {
const [form, setForm] = useState<Partial<AddFreeAgentPostVars>>(
post ? post : {}
)
const [showErrors, setShowErrors] = useState(false)
const [deleting, setDeleting] = useState(false)
const toast = useToast()
const { themeColor, grayWithShade } = useContext(MyThemeContext)
const [addFreeAgentPost] = useMutation<boolean, AddFreeAgentPostVars>(
ADD_FREE_AGENT_POST,
{
variables: { ...(form as AddFreeAgentPostVars) },
onCompleted: data => {
closeModal()
toast({
description: `Free agent post added`,
position: "top-right",
status: "success",
duration: 10000,
})
},
onError: error => {
toast({
title: "An error occurred",
description: error.message,
position: "top-right",
status: "error",
duration: 10000,
})
},
refetchQueries: [{ query: FREE_AGENT_POSTS }],
}
)
const [editFreeAgentPost] = useMutation<boolean, AddFreeAgentPostVars>(
UPDATE_FREE_AGENT_POST,
{
variables: { ...(form as AddFreeAgentPostVars) },
onCompleted: data => {
closeModal()
toast({
description: `Free agent post edited`,
position: "top-right",
status: "success",
duration: 10000,
})
},
onError: error => {
toast({
title: "An error occurred",
description: error.message,
position: "top-right",
status: "error",
duration: 10000,
})
},
refetchQueries: [{ query: FREE_AGENT_POSTS }],
}
)
const [hideFreeAgentPost] = useMutation<boolean, AddFreeAgentPostVars>(
HIDE_FREE_AGENT_POST,
{
variables: { ...(form as AddFreeAgentPostVars) },
onCompleted: data => {
closeModal()
toast({
description: `Free agent post deleted`,
position: "top-right",
status: "success",
duration: 10000,
})
},
onError: error => {
toast({
title: "An error occurred",
description: error.message,
position: "top-right",
status: "error",
duration: 10000,
})
},
refetchQueries: [{ query: FREE_AGENT_POSTS }],
}
)
const handleChange = (newValueObject: Partial<AddFreeAgentPostVars>) => {
setForm({ ...form, ...newValueObject })
}
const actionType = post ? "EDIT" : "NEW"
const handleSubmit = () => {
if (
form.playstyles?.length === 0 ||
!form.can_vc ||
(form.past_experience ?? "").length > 100 ||
(form.activity ?? "").length > 100 ||
(form.looking_for ?? "").length > 100 ||
(form.description ?? "").length > 1000
) {
setShowErrors(true)
return
}
if (actionType === "NEW") addFreeAgentPost()
if (actionType === "EDIT") editFreeAgentPost()
}
return (
<Modal
title={
actionType === "NEW"
? "Adding a new free agent post"
: "Editing a free agent post"
}
closeModal={closeModal}
>
{actionType === "EDIT" && (
<Box
color="red.500"
mb="1em"
textDecoration="underline"
cursor="pointer"
onClick={() => setDeleting(true)}
>
Delete free agent post
</Box>
)}
{deleting && (
<>
<Box color={grayWithShade}>
Note that if you decide to delete your post you need to wait a week
before posting a new one.
</Box>
<Flex flexWrap="wrap" mt="1em">
<Box mr="1em">
<Button onClick={() => hideFreeAgentPost()}>
Confirm deletion
</Button>
</Box>
<Button outlined onClick={() => setDeleting(false)}>
Cancel
</Button>
</Flex>
</>
)}
{actionType === "NEW" && (
<Alert status="info">
Profile picture, Discord name, Twitter user, weapon pool and Top 500
history are automatically synced up with your profile. Also please
note that the post automatically sent to Discord can't be edited
afterwardsso you want to set these before making a post.
</Alert>
)}
<FormControl
isRequired
isInvalid={showErrors && form.playstyles?.length === 0}
mt="1em"
>
<FormLabel htmlFor="playstyles">Playstyles</FormLabel>
<CheckboxGroup
id="playstyles"
variantColor={themeColor}
value={form.playstyles ?? []}
onChange={value =>
handleChange({
playstyles: value as ("FRONTLINE" | "MIDLINE" | "BACKLINE")[],
})
}
>
<Checkbox value="FRONTLINE">Frontline/Slayer</Checkbox>
<Checkbox value="MIDLINE">Midline/Support</Checkbox>
<Checkbox value="BACKLINE">Backline/Anchor</Checkbox>
</CheckboxGroup>
<FormErrorMessage>Required field</FormErrorMessage>
</FormControl>
<FormControl isRequired isInvalid={showErrors && !form.can_vc} mt="1em">
<FormLabel htmlFor="canVc">Can you voice chat?</FormLabel>
<RadioGroup
id="canVc"
variantColor={themeColor}
value={form.can_vc}
onChange={(e, value) =>
handleChange({
can_vc: value as "YES" | "USUALLY" | "SOMETIMES" | "NO",
})
}
>
<Radio value="YES">Yes</Radio>
<Radio value="USUALLY">Usually</Radio>
<Radio value="SOMETIMES">Sometimes</Radio>
<Radio value="NO">No</Radio>
</RadioGroup>
<FormErrorMessage>Required field</FormErrorMessage>
</FormControl>
<FormControl
isInvalid={
showErrors &&
!!form.past_experience &&
form.past_experience.length > 100
}
mt="1em"
>
<FormLabel htmlFor="pastExperience">
Past competitive experience
</FormLabel>
<TextArea
id="pastExperience"
setValue={(value: string) =>
handleChange({ past_experience: value as string })
}
value={form.past_experience ?? ""}
limit={100}
/>
<FormErrorMessage>Value too long</FormErrorMessage>
</FormControl>
<FormControl
isInvalid={showErrors && !!form.activity && form.activity.length > 100}
mt="1em"
>
<FormLabel htmlFor="activity">
What is your activity like on a typical week?
</FormLabel>
<TextArea
id="activity"
setValue={(value: string) =>
handleChange({ activity: value as string })
}
value={form.activity ?? ""}
limit={100}
/>
<FormErrorMessage>Value too long</FormErrorMessage>
</FormControl>
<FormControl
isInvalid={
showErrors && !!form.looking_for && form.looking_for.length > 100
}
mt="1em"
>
<FormLabel htmlFor="lookingFor">
What are you looking from a team?
</FormLabel>
<TextArea
id="lookingFor"
setValue={(value: string) =>
handleChange({ looking_for: value as string })
}
value={form.looking_for ?? ""}
limit={100}
/>
<FormErrorMessage>Value too long</FormErrorMessage>
</FormControl>
<FormControl
isInvalid={
showErrors && !!form.description && form.description.length > 1000
}
mt="1em"
>
<FormLabel htmlFor="lookingFor">Free word</FormLabel>
<TextArea
id="lookingFor"
setValue={(value: string) =>
handleChange({ description: value as string })
}
value={form.description ?? ""}
height="150px"
limit={1000}
/>
<FormErrorMessage>Value too long</FormErrorMessage>
</FormControl>
<Flex flexWrap="wrap" mt="1em">
<Box mr="1em">
<Button onClick={() => handleSubmit()}>Submit</Button>
</Box>
<Button outlined onClick={() => closeModal()}>
Cancel
</Button>
</Flex>
</Modal>
)
}
export default FAPostModal

View File

@@ -21,6 +21,7 @@ import { continents } from "../../utils/lists"
import { Collapse, Flex } from "@chakra-ui/core"
import Button from "../elements/Button"
import { FaFilter } from "react-icons/fa"
import FAPostModal from "./FAPostModal"
const playstyleToEnum = {
"Frontline/Slayer": "FRONTLINE",
@@ -103,6 +104,7 @@ const FreeAgentsPage: React.FC<RouteComponentProps> = () => {
const showModalButton = () => {
if (!userData.user) return false
console.log("ownFAPost", ownFAPost)
if (ownFAPost && ownFAPost.hidden) {
const weekFromCreatingFAPost = parseInt(ownFAPost.createdAt) + 604800000
@@ -120,17 +122,18 @@ const FreeAgentsPage: React.FC<RouteComponentProps> = () => {
<title>Free Agents | sendou.ink</title>
</Helmet>
<PageHeader title="Free Agents" />
{showModal && (
<FAPostModal closeModal={() => setShowModal(false)} post={ownFAPost} />
)}
<Flex justifyContent="space-between" flexWrap="wrap">
<Box m="0.5em">
<Button icon={FaFilter} onClick={() => setShowFilters(!showFilters)}>
{showFilters ? "Hide filters" : "Show filters"}
</Button>
</Box>
{showModalButton && (
{showModalButton() && (
<Box m="0.5em">
<Button onClick={() => setShowModal(true)}>
{buttonText} (coming back soon)
</Button>
<Button onClick={() => setShowModal(true)}>{buttonText}</Button>
</Box>
)}
</Flex>

View File

@@ -29,8 +29,8 @@ const Posts: React.FC<PostsAccordionProps> = ({ posts }) => {
{posts
.filter((post, index) => index < agentsToShow)
.map(post => (
<Box my="1em">
<FreeAgentCard key={post.id} post={post} />
<Box my="1em" key={post.id}>
<FreeAgentCard post={post} />
</Box>
))}
</InfiniteScroll>

View File

@@ -128,7 +128,7 @@ const SuggestionVouchModal: React.FC<SuggestionVouchModalProps> = ({
}
return (
<Modal title={"Suggesting or vouching a player"} closeModal={closeModal}>
<Modal title="Suggesting or vouching a player" closeModal={closeModal}>
<FormControl isRequired isInvalid={showErrors && !form.discord_id}>
<FormLabel htmlFor="user">Discord username</FormLabel>
<UserSelector
@@ -142,8 +142,9 @@ const SuggestionVouchModal: React.FC<SuggestionVouchModalProps> = ({
</FormControl>
<FormControl isRequired mt="1em">
<FormLabel htmlFor="server">Action</FormLabel>
<FormLabel htmlFor="action">Action</FormLabel>
<RadioGroup
id="action"
spacing={5}
isInline
onChange={(e, value) => setActionType(value as string)}

View File

@@ -1,21 +0,0 @@
import { gql } from "apollo-boost"
export const addFreeAgentPost = gql`
mutation addFreeAgentPost(
$can_vc: CanVC!
$playstyles: [Playstyle!]
$activity: String
$looking_for: String
$past_experience: String
$description: String
) {
addFreeAgentPost(
can_vc: $can_vc
playstyles: $playstyles
activity: $activity
looking_for: $looking_for
past_experience: $past_experience
description: $description
)
}
`

View File

@@ -0,0 +1,30 @@
import { gql, DocumentNode } from "apollo-boost"
export interface AddFreeAgentPostVars {
can_vc: "YES" | "USUALLY" | "SOMETIMES" | "NO"
playstyles: ("FRONTLINE" | "MIDLINE" | "BACKLINE")[]
activity?: string
looking_for?: string
past_experience?: string
description?: string
}
export const ADD_FREE_AGENT_POST: DocumentNode = gql`
mutation addFreeAgentPost(
$can_vc: CanVC!
$playstyles: [Playstyle!]!
$activity: String
$looking_for: String
$past_experience: String
$description: String
) {
addFreeAgentPost(
can_vc: $can_vc
playstyles: $playstyles
activity: $activity
looking_for: $looking_for
past_experience: $past_experience
description: $description
)
}
`

View File

@@ -1,7 +0,0 @@
import { gql } from "apollo-boost"
export const hideFreeAgentPost = gql`
mutation hideFreeAgentPost {
hideFreeAgentPost
}
`

View File

@@ -0,0 +1,7 @@
import { gql, DocumentNode } from "apollo-boost"
export const HIDE_FREE_AGENT_POST: DocumentNode = gql`
mutation hideFreeAgentPost {
hideFreeAgentPost
}
`

View File

@@ -1,9 +1,9 @@
import { gql } from "apollo-boost"
import { gql, DocumentNode } from "apollo-boost"
export const updateFreeAgentPost = gql`
export const UPDATE_FREE_AGENT_POST: DocumentNode = gql`
mutation updateFreeAgentPost(
$can_vc: CanVC!
$playstyles: [Playstyle!]
$playstyles: [Playstyle!]!
$activity: String
$looking_for: String
$past_experience: String

View File

@@ -1,28 +0,0 @@
import { gql } from "apollo-boost"
export const searchForBuildsByWeapon = gql`
query searchForBuildsByWeapon($weapon: String, $page: Int) {
searchForBuildsByWeapon(weapon: $weapon, page: $page) {
builds {
id
discord_id
top
weapon
headgear
headgearItem
clothing
clothingItem
shoes
shoesItem
title
description
updatedAt
discord_user {
username
discriminator
}
}
pageCount
}
}
`

View File

@@ -1,4 +1,8 @@
const { UserInputError, gql } = require("apollo-server-express")
const {
UserInputError,
AuthenticationError,
gql,
} = require("apollo-server-express")
const FAPost = require("../mongoose-models/fapost")
const sendFAPostToDiscord = require("../utils/webhook")
@@ -13,7 +17,7 @@ const typeDef = gql`
extend type Mutation {
addFreeAgentPost(
can_vc: CanVC!
playstyles: [Playstyle!]
playstyles: [Playstyle!]!
activity: String
looking_for: String
past_experience: String
@@ -22,7 +26,7 @@ const typeDef = gql`
hideFreeAgentPost: Boolean!
updateFreeAgentPost(
can_vc: CanVC!
playstyles: [Playstyle!]
playstyles: [Playstyle!]!
activity: String
looking_for: String
past_experience: String