mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-27 13:45:27 -05:00
fapost create update delete
This commit is contained in:
@@ -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 && (
|
||||
|
||||
@@ -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"
|
||||
|
||||
324
frontend-react/src/components/freeagents/FAPostModal.tsx
Normal file
324
frontend-react/src/components/freeagents/FAPostModal.tsx
Normal 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
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
`
|
||||
30
frontend-react/src/graphql/mutations/addFreeAgentPost.ts
Normal file
30
frontend-react/src/graphql/mutations/addFreeAgentPost.ts
Normal 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
|
||||
)
|
||||
}
|
||||
`
|
||||
@@ -1,7 +0,0 @@
|
||||
import { gql } from "apollo-boost"
|
||||
|
||||
export const hideFreeAgentPost = gql`
|
||||
mutation hideFreeAgentPost {
|
||||
hideFreeAgentPost
|
||||
}
|
||||
`
|
||||
@@ -0,0 +1,7 @@
|
||||
import { gql, DocumentNode } from "apollo-boost"
|
||||
|
||||
export const HIDE_FREE_AGENT_POST: DocumentNode = gql`
|
||||
mutation hideFreeAgentPost {
|
||||
hideFreeAgentPost
|
||||
}
|
||||
`
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
`
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user