From 41a8474af10511fc02286a7ae0832128a6c62327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Tue, 19 Mar 2024 14:35:54 +0900 Subject: [PATCH 01/35] =?UTF-8?q?=20[Refactoring=20=E2=9A=99=EF=B8=8F]=20c?= =?UTF-8?q?lose=EB=B2=84=ED=8A=BC=20=ED=81=B4=EB=A6=AD=EC=8B=9C=EC=97=90?= =?UTF-8?q?=EB=A7=8C=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EB=B0=9C=EC=83=9D?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Tag/components/CloseButtonTag.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/Tag/components/CloseButtonTag.tsx b/src/components/Tag/components/CloseButtonTag.tsx index 62499e7b..790ab7f3 100644 --- a/src/components/Tag/components/CloseButtonTag.tsx +++ b/src/components/Tag/components/CloseButtonTag.tsx @@ -4,7 +4,8 @@ import { MdCancel } from "react-icons/md" import { CommonTagProps } from "../types/commonTagProps" import CommonTag from "./CommonTag" -interface CloseButtonTagProps extends Omit { +interface CloseButtonTagProps + extends Omit { onClickCloseButton: MouseEventHandler } @@ -17,6 +18,9 @@ const CloseButtonTag = ({ return ( { + e.preventDefault() + }} label={label} rightElement={ Date: Tue, 19 Mar 2024 14:40:47 +0900 Subject: [PATCH 02/35] =?UTF-8?q?=20[Change=20=F0=9F=9A=9C=20]=20styles=20?= =?UTF-8?q?=ED=8F=B4=EB=8D=94=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20Container?= =?UTF-8?q?=20=ED=8C=8C=EC=9D=BC=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProjectEditPage/components/{ => styles}/FieldContainer.tsx | 1 + 1 file changed, 1 insertion(+) rename src/pages/ProjectEditPage/components/{ => styles}/FieldContainer.tsx (94%) diff --git a/src/pages/ProjectEditPage/components/FieldContainer.tsx b/src/pages/ProjectEditPage/components/styles/FieldContainer.tsx similarity index 94% rename from src/pages/ProjectEditPage/components/FieldContainer.tsx rename to src/pages/ProjectEditPage/components/styles/FieldContainer.tsx index fb8813f2..88749452 100644 --- a/src/pages/ProjectEditPage/components/FieldContainer.tsx +++ b/src/pages/ProjectEditPage/components/styles/FieldContainer.tsx @@ -5,6 +5,7 @@ import { Flex } from "@chakra-ui/react" const FieldContainer = ({ children }: PropsWithChildren) => ( Date: Tue, 19 Mar 2024 15:19:40 +0900 Subject: [PATCH 03/35] =?UTF-8?q?=20[Feat=20=E2=9C=8F=EF=B8=8F]=20useDebou?= =?UTF-8?q?nce=20hook=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useDebounce.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/hooks/useDebounce.ts diff --git a/src/hooks/useDebounce.ts b/src/hooks/useDebounce.ts new file mode 100644 index 00000000..0c407cda --- /dev/null +++ b/src/hooks/useDebounce.ts @@ -0,0 +1,17 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { useRef } from "react" + +export const useDebounce = ( + callback: (...params: T) => void, + time: number, +) => { + const timer = useRef | null>(null) + return (...params: T) => { + if (timer.current) clearTimeout(timer.current) + + timer.current = setTimeout(() => { + callback(...params) + timer.current = null + }, time) + } +} From 2420e108a1d5b8a60a728109bbfd6eb8d147b601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Tue, 19 Mar 2024 15:23:28 +0900 Subject: [PATCH 04/35] =?UTF-8?q?=20[Feat=20=E2=9C=8F=EF=B8=8F]=20useInput?= =?UTF-8?q?=20debounce=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Search/hooks/useInput.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/components/Search/hooks/useInput.ts b/src/components/Search/hooks/useInput.ts index a9360105..a51f6ed9 100644 --- a/src/components/Search/hooks/useInput.ts +++ b/src/components/Search/hooks/useInput.ts @@ -1,12 +1,15 @@ -import { ChangeEventHandler, useCallback, useState } from "react" +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { ChangeEventHandler, useState } from "react" -export const useInput = (initialValue = "") => { +import { useDebounce } from "@hooks/useDebounce" + +export const useInput = (initialValue = "", timer = 500) => { const [inputValue, setInputValue] = useState(initialValue) - const onInput: ChangeEventHandler = useCallback((e) => { + const onInput: ChangeEventHandler = useDebounce((e) => { const inputValue = e.target.value.trim() setInputValue(inputValue) - }, []) + }, timer) return [inputValue, onInput] as const } From d7e5915a3989f26fcd2cd5b3cf321ddd1dfbf72c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Tue, 19 Mar 2024 15:23:56 +0900 Subject: [PATCH 05/35] =?UTF-8?q?=20[Refactoring=20=E2=9A=99=EF=B8=8F]=20S?= =?UTF-8?q?earchBar=20=EB=B9=84=EC=A0=9C=EC=96=B4=EB=B0=A9=EC=8B=9D?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=82=AC=EC=9A=A9=20=EA=B0=80=EB=8A=A5?= =?UTF-8?q?=ED=95=98=EA=B2=8C=20=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Search/components/SearchBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Search/components/SearchBar.tsx b/src/components/Search/components/SearchBar.tsx index e3bb96bf..51910c72 100644 --- a/src/components/Search/components/SearchBar.tsx +++ b/src/components/Search/components/SearchBar.tsx @@ -3,7 +3,7 @@ import { ChangeEventHandler } from "react" import { Input, InputProps } from "@chakra-ui/react" interface SearchBarProps extends Omit { - value: string + value?: string onChange: ChangeEventHandler } From 419a28daa2dd6b57538ba8bb290f923c8452db37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Tue, 19 Mar 2024 15:25:17 +0900 Subject: [PATCH 06/35] =?UTF-8?q?=20[Refactoring=20=E2=9A=99=EF=B8=8F]=20i?= =?UTF-8?q?mport=20=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProjectEditPage/components/MemberFields/MemberFields.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ProjectEditPage/components/MemberFields/MemberFields.tsx b/src/pages/ProjectEditPage/components/MemberFields/MemberFields.tsx index 10ef90c1..9884f35c 100644 --- a/src/pages/ProjectEditPage/components/MemberFields/MemberFields.tsx +++ b/src/pages/ProjectEditPage/components/MemberFields/MemberFields.tsx @@ -4,7 +4,7 @@ import { Button, Flex, Input } from "@chakra-ui/react" import AvatarCard from "@components/AvatarCard/AvatarCard" -import FieldContainer from "../FieldContainer" +import FieldContainer from "../styles/FieldContainer" import UserSearchBox from "./components/UserSearchBox" import { useMemberFieldsMethods } from "./hooks/useMemberFieldsMethods" From 3e70b43faea465b053f8f8463a194fd626a46b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Tue, 19 Mar 2024 15:26:07 +0900 Subject: [PATCH 07/35] =?UTF-8?q?=20[Feat=20=E2=9C=8F=EF=B8=8F]=20SearchRe?= =?UTF-8?q?sultContainer=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../styles/SearchResultContainer.tsx | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/pages/ProjectEditPage/components/styles/SearchResultContainer.tsx diff --git a/src/pages/ProjectEditPage/components/styles/SearchResultContainer.tsx b/src/pages/ProjectEditPage/components/styles/SearchResultContainer.tsx new file mode 100644 index 00000000..d0a9510e --- /dev/null +++ b/src/pages/ProjectEditPage/components/styles/SearchResultContainer.tsx @@ -0,0 +1,26 @@ +import { ReactNode } from "react" + +import { Flex, FlexProps } from "@chakra-ui/react" + +interface SearchResultContainerProps extends FlexProps { + children?: ReactNode +} + +const SearchResultContainer = ({ children }: SearchResultContainerProps) => { + return ( + + {children} + + ) +} + +export default SearchResultContainer From a49033b224c33c9548da4817fda40a573cfa6578 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Tue, 19 Mar 2024 15:26:32 +0900 Subject: [PATCH 08/35] =?UTF-8?q?=20[Feat=20=E2=9C=8F=EF=B8=8F]=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20remove=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TechStacksFields/hooks/useTechStacksMethods.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pages/ProjectEditPage/components/TechStacksFields/hooks/useTechStacksMethods.ts b/src/pages/ProjectEditPage/components/TechStacksFields/hooks/useTechStacksMethods.ts index 032e15a7..f8570e3c 100644 --- a/src/pages/ProjectEditPage/components/TechStacksFields/hooks/useTechStacksMethods.ts +++ b/src/pages/ProjectEditPage/components/TechStacksFields/hooks/useTechStacksMethods.ts @@ -8,7 +8,7 @@ import { ProjectFormValues } from "@pages/ProjectEditPage/types/ProjectFormValue export const useTechStacksMethods = () => { const { control, setValue, getValues, watch } = useProjectFormContext() - const { append, fields } = useFieldArray({ + const { append, fields, remove } = useFieldArray({ control, name: "techStacks", }) @@ -32,6 +32,8 @@ export const useTechStacksMethods = () => { setValue(`techStacks.${index}.stacks`, [...filtered]) } + const removeField = (idx: number) => remove(idx) + const selectedStacks = (index: number) => watch(`techStacks.${index}.stacks`) return { @@ -43,5 +45,6 @@ export const useTechStacksMethods = () => { appendStack, removeStack, selectedStacks, + removeField, } } From f71cf638c3dfe5b07bb1f0fa86563d3add0395a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Tue, 19 Mar 2024 15:33:37 +0900 Subject: [PATCH 09/35] =?UTF-8?q?=20[Feat=20=E2=9C=8F=EF=B8=8F]=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=82=AD=EC=A0=9C=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=8A=A4=ED=83=80=EC=9D=BC=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TechStacksFields/TechStackFields.tsx | 55 ++++++++++++++++--- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/src/pages/ProjectEditPage/components/TechStacksFields/TechStackFields.tsx b/src/pages/ProjectEditPage/components/TechStacksFields/TechStackFields.tsx index 6a27b2fc..aa638b26 100644 --- a/src/pages/ProjectEditPage/components/TechStacksFields/TechStackFields.tsx +++ b/src/pages/ProjectEditPage/components/TechStacksFields/TechStackFields.tsx @@ -1,13 +1,23 @@ import { Controller } from "react-hook-form" +import { MdClose } from "react-icons/md" -import { Box, Button, Flex, Input } from "@chakra-ui/react" +import { + AbsoluteCenter, + Box, + Button, + Flex, + Image, + Input, +} from "@chakra-ui/react" import CloseButtonTag from "@components/Tag/components/CloseButtonTag" +import CommonTag from "@components/Tag/components/CommonTag" import { useTechStacksMethods } from "@pages/ProjectEditPage/components/TechStacksFields/hooks/useTechStacksMethods" import { filterSelectedId } from "@pages/ProjectEditPage/utils/filterSelectedId" -import FieldContainer from "../FieldContainer" +import FieldContainer from "../styles/FieldContainer" +import SearchResultContainer from "../styles/SearchResultContainer" import StackSearchBox from "./components/StackSearchBox" const TechStacksFields = () => { @@ -15,6 +25,7 @@ const TechStacksFields = () => { fields, control, appendNewFields, + removeField, appendStack, selectedStacks, removeStack, @@ -32,13 +43,24 @@ const TechStacksFields = () => { name={`techStacks.${index}.category`} control={control} rules={{ required: true }} - render={({ field }) => } + render={({ field }) => ( + + )} /> + { return ( - + + {!techStacks.length && ( + + 검색 결과가 존재하지 않습니다 + + )} {filterSelectedId(techStacks, selectedStacks(index)).map( (techStack) => { return ( @@ -46,16 +68,27 @@ const TechStacksFields = () => { cursor="pointer" onClick={() => appendStack(index, techStack)} key={techStack.name}> - {techStack.name} + + } + label={techStack.name} + border="none" + /> ) }, )} - + ) }} /> - + {selectedStacks(index).map((stack) => ( { /> ))} + removeField(index)}> + + ) })} From 4e1e76ca1384bef8ed798b559941237422026645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Tue, 19 Mar 2024 15:36:55 +0900 Subject: [PATCH 10/35] =?UTF-8?q?=20[Refactoring=20=E2=9A=99=EF=B8=8F]=20d?= =?UTF-8?q?ebounce=20=EC=A0=81=EC=9A=A9=20=EC=9C=84=ED=95=B4=20=EB=B9=84?= =?UTF-8?q?=EC=A0=9C=EC=96=B4=20=EB=B0=A9=EC=8B=9D=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/TechStacksFields/components/StackSearchBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ProjectEditPage/components/TechStacksFields/components/StackSearchBox.tsx b/src/pages/ProjectEditPage/components/TechStacksFields/components/StackSearchBox.tsx index bceeed83..4a50fcfc 100644 --- a/src/pages/ProjectEditPage/components/TechStacksFields/components/StackSearchBox.tsx +++ b/src/pages/ProjectEditPage/components/TechStacksFields/components/StackSearchBox.tsx @@ -26,13 +26,13 @@ const StackSearchBox = ({ gap="0.5rem" flexWrap="wrap"> {children} {render({ techStacks })} From 75e4b7633f4dc79cfd57a6ebb0a926eac4fc0462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Tue, 19 Mar 2024 15:37:43 +0900 Subject: [PATCH 11/35] =?UTF-8?q?=20[Design=20=F0=9F=8E=A8]=20=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=95=84=EC=9B=83=20div=20->=20flex=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/ProjectEditPage/components/ProjectInputBox.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pages/ProjectEditPage/components/ProjectInputBox.tsx b/src/pages/ProjectEditPage/components/ProjectInputBox.tsx index 38ceedb6..9c3eaaa4 100644 --- a/src/pages/ProjectEditPage/components/ProjectInputBox.tsx +++ b/src/pages/ProjectEditPage/components/ProjectInputBox.tsx @@ -1,7 +1,7 @@ import { ReactElement, cloneElement, isValidElement } from "react" import { useFormContext } from "react-hook-form" -import { Box, BoxProps, InputElementProps, Text } from "@chakra-ui/react" +import { BoxProps, Flex, InputElementProps, Text } from "@chakra-ui/react" import { projectInputRegister } from "../constants/registerOptions" import { ProjectFormValues } from "../types/ProjectFormValues" @@ -20,7 +20,9 @@ const ProjectInputBox = ({ name, label, footer, children }: TextInputProps) => { } = useFormContext() return ( - + + ) } From 0e45cd7e5119be80d4c21b391f08344c8726b4bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Tue, 19 Mar 2024 20:21:40 +0900 Subject: [PATCH 12/35] =?UTF-8?q?=20[Refactoring=20=E2=9A=99=EF=B8=8F]=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hooks/useMemberFieldsMethods.ts | 30 ++-- .../TechStacksFields/TechStackFields.tsx | 158 +++++++++--------- .../hooks/useTechStacksMethods.ts | 16 +- .../types/ProjectFormValues.ts | 8 +- 4 files changed, 104 insertions(+), 108 deletions(-) diff --git a/src/pages/ProjectEditPage/components/MemberFields/hooks/useMemberFieldsMethods.ts b/src/pages/ProjectEditPage/components/MemberFields/hooks/useMemberFieldsMethods.ts index 2318bcb4..f667deb7 100644 --- a/src/pages/ProjectEditPage/components/MemberFields/hooks/useMemberFieldsMethods.ts +++ b/src/pages/ProjectEditPage/components/MemberFields/hooks/useMemberFieldsMethods.ts @@ -1,21 +1,11 @@ -import { useFieldArray, useFormContext } from "react-hook-form" +import { useFieldArray } from "react-hook-form" -type RequestedMemberType = { - id: number | null - nickname: string - profileImageUrl: string | null -} +import { useProjectFormContext } from "@pages/ProjectEditPage/hooks/useProjectFormContext" +import { RequestedMemberType } from "@pages/ProjectEditPage/types/ProjectFormValues" -type MemberFieldValues = { - members: { - category: string - members: RequestedMemberType[] - }[] -} -//react-hook-form의 formProvider와 같이 사용해야함 export const useMemberFieldsMethods = () => { const { control, getValues, setValue, watch, register } = - useFormContext() + useProjectFormContext() const { fields, append, remove } = useFieldArray({ name: "members", @@ -23,7 +13,7 @@ export const useMemberFieldsMethods = () => { }) const appendNewFields = () => { - append({ category: "", members: [] }) + append({ category: "", data: [] }) } const deleteFields = (idx: number) => { @@ -35,19 +25,19 @@ export const useMemberFieldsMethods = () => { } const appendMembers = (data: RequestedMemberType, idx: number) => { - const members = [...getValues(`members.${idx}.members`), data] - setValue(`members.${idx}.members`, members) + const members = [...getValues(`members.${idx}.data`), data] + setValue(`members.${idx}.data`, members) } const removeMembers = (data: RequestedMemberType, idx: number) => { - const members = [...getValues(`members.${idx}.members`)] + const members = [...getValues(`members.${idx}.data`)] setValue( - `members.${idx}.members`, + `members.${idx}.data`, members.filter((member) => member.id !== data.id), ) } - const getSelectedMembers = (idx: number) => watch(`members.${idx}.members`) + const getSelectedMembers = (idx: number) => watch(`members.${idx}.data`) return { fields, diff --git a/src/pages/ProjectEditPage/components/TechStacksFields/TechStackFields.tsx b/src/pages/ProjectEditPage/components/TechStacksFields/TechStackFields.tsx index aa638b26..7920ea4c 100644 --- a/src/pages/ProjectEditPage/components/TechStacksFields/TechStackFields.tsx +++ b/src/pages/ProjectEditPage/components/TechStacksFields/TechStackFields.tsx @@ -14,6 +14,7 @@ import CloseButtonTag from "@components/Tag/components/CloseButtonTag" import CommonTag from "@components/Tag/components/CommonTag" import { useTechStacksMethods } from "@pages/ProjectEditPage/components/TechStacksFields/hooks/useTechStacksMethods" +import { projectInputRegister } from "@pages/ProjectEditPage/constants/registerOptions" import { filterSelectedId } from "@pages/ProjectEditPage/utils/filterSelectedId" import FieldContainer from "../styles/FieldContainer" @@ -29,87 +30,90 @@ const TechStacksFields = () => { appendStack, selectedStacks, removeStack, + register, } = useTechStacksMethods() return ( - - {fields.map((field, index) => { - return ( - - - ( - - )} - /> - - - { - return ( - - {!techStacks.length && ( - - 검색 결과가 존재하지 않습니다 - - )} - {filterSelectedId(techStacks, selectedStacks(index)).map( - (techStack) => { - return ( - appendStack(index, techStack)} - key={techStack.name}> - - } - label={techStack.name} - border="none" - /> - - ) - }, - )} - - ) - }} - /> - - {selectedStacks(index).map((stack) => ( - removeStack(index, stack)} +
+ + {fields.map((field, index) => { + return ( + + + ( + + )} /> - ))} - - removeField(index)}> - - - - ) - })} - - + + + { + return ( + + {!techStacks.length && ( + + 검색 결과가 존재하지 않습니다 + + )} + {filterSelectedId(techStacks, selectedStacks(index)).map( + (techStack) => { + return ( + appendStack(index, techStack)} + key={techStack.name}> + + } + label={techStack.name} + border="none" + /> + + ) + }, + )} + + ) + }} + /> + + {selectedStacks(index).map((stack) => ( + removeStack(index, stack)} + /> + ))} + + removeField(index)}> + + + + ) + })} + + +
) } export default TechStacksFields diff --git a/src/pages/ProjectEditPage/components/TechStacksFields/hooks/useTechStacksMethods.ts b/src/pages/ProjectEditPage/components/TechStacksFields/hooks/useTechStacksMethods.ts index f8570e3c..952b07db 100644 --- a/src/pages/ProjectEditPage/components/TechStacksFields/hooks/useTechStacksMethods.ts +++ b/src/pages/ProjectEditPage/components/TechStacksFields/hooks/useTechStacksMethods.ts @@ -6,7 +6,8 @@ import { useProjectFormContext } from "@pages/ProjectEditPage/hooks/useProjectFo import { ProjectFormValues } from "@pages/ProjectEditPage/types/ProjectFormValues" export const useTechStacksMethods = () => { - const { control, setValue, getValues, watch } = useProjectFormContext() + const { control, setValue, getValues, watch, register } = + useProjectFormContext() const { append, fields, remove } = useFieldArray({ control, @@ -14,7 +15,7 @@ export const useTechStacksMethods = () => { }) const appendNewFields = () => { - append({ category: "", stacks: [] }) + append({ category: "", data: [] }) } const setCategory = (index: number, value: string) => { @@ -22,19 +23,19 @@ export const useTechStacksMethods = () => { } const appendStack = (index: number, element: Skill) => { - const stacks = getValues(`techStacks.${index}.stacks`) - setValue(`techStacks.${index}.stacks`, [...stacks, element]) + const stacks = getValues(`techStacks.${index}.data`) + setValue(`techStacks.${index}.data`, [...stacks, element]) } const removeStack = (index: number, element: Skill) => { - const stacks = getValues(`techStacks.${index}.stacks`) + const stacks = getValues(`techStacks.${index}.data`) const filtered = stacks.filter((stack) => stack.id !== element.id) - setValue(`techStacks.${index}.stacks`, [...filtered]) + setValue(`techStacks.${index}.data`, [...filtered]) } const removeField = (idx: number) => remove(idx) - const selectedStacks = (index: number) => watch(`techStacks.${index}.stacks`) + const selectedStacks = (index: number) => watch(`techStacks.${index}.data`) return { fields, @@ -46,5 +47,6 @@ export const useTechStacksMethods = () => { removeStack, selectedStacks, removeField, + register, } } diff --git a/src/pages/ProjectEditPage/types/ProjectFormValues.ts b/src/pages/ProjectEditPage/types/ProjectFormValues.ts index 63e07d95..6f937327 100644 --- a/src/pages/ProjectEditPage/types/ProjectFormValues.ts +++ b/src/pages/ProjectEditPage/types/ProjectFormValues.ts @@ -1,9 +1,9 @@ import { Skill } from "api-models" -export type FieldMember = { +export type RequestedMemberType = { id: number | null nickname: string - role: string + profileImageUrl: string | null } export type ProjectFormValues = { @@ -16,8 +16,8 @@ export type ProjectFormValues = { deployUrl: string startDate: string endDate: string - techStacks: { category: string; stacks: Skill[] }[] + techStacks: { category: string; data: Skill[] }[] description: string troubleShooting: string - members: { category: string; members: FieldMember[] }[] + members: { category: string; data: RequestedMemberType[] }[] } From 0dfae9ff8b038377bc2142af314798da754ac5d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Tue, 19 Mar 2024 20:33:48 +0900 Subject: [PATCH 13/35] =?UTF-8?q?=20[Feat=20=E2=9C=8F=EF=B8=8F]=20fields?= =?UTF-8?q?=20data=20=EB=B0=B0=EC=97=B4=20=EC=A4=91=20=EB=B9=88=20?= =?UTF-8?q?=EB=B0=B0=EC=97=B4=20=EC=A1=B0=EC=82=AC=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EC=9C=A0=ED=8B=B8=ED=95=A8=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProjectEditPage/utils/checkEmptyField.test.ts | 12 ++++++++++++ src/pages/ProjectEditPage/utils/checkEmptyField.ts | 5 +++++ 2 files changed, 17 insertions(+) create mode 100644 src/pages/ProjectEditPage/utils/checkEmptyField.test.ts create mode 100644 src/pages/ProjectEditPage/utils/checkEmptyField.ts diff --git a/src/pages/ProjectEditPage/utils/checkEmptyField.test.ts b/src/pages/ProjectEditPage/utils/checkEmptyField.test.ts new file mode 100644 index 00000000..b0fad336 --- /dev/null +++ b/src/pages/ProjectEditPage/utils/checkEmptyField.test.ts @@ -0,0 +1,12 @@ +import { expect, test } from "vitest" + +import { checkEmptyField } from "./checkEmptyField" + +test("필드 값 중 빈 배열이 있을 경우 false를 리턴한다", () => { + const fields: { category: string; data: string[] }[] = [ + { category: "백엔드", data: ["a", "b", "c"] }, + { category: "", data: ["c", "a", "b"] }, + { category: " ", data: [] }, + ] + expect(checkEmptyField(fields)).toBe(true) +}) diff --git a/src/pages/ProjectEditPage/utils/checkEmptyField.ts b/src/pages/ProjectEditPage/utils/checkEmptyField.ts new file mode 100644 index 00000000..b2c79643 --- /dev/null +++ b/src/pages/ProjectEditPage/utils/checkEmptyField.ts @@ -0,0 +1,5 @@ +export const checkEmptyField = ( + fields: { category: string; data: T[] }[], +) => { + return fields.some((field) => field.data.length === 0) +} From 5addf8e07404c2572fc514cd0e98cec44dbb7444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Wed, 20 Mar 2024 01:33:14 +0900 Subject: [PATCH 14/35] =?UTF-8?q?=20[Design=20=F0=9F=8E=A8]=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=EC=8A=A4=ED=83=80=EC=9D=BC=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TechStacksFields/components/StackSearchBox.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/pages/ProjectEditPage/components/TechStacksFields/components/StackSearchBox.tsx b/src/pages/ProjectEditPage/components/TechStacksFields/components/StackSearchBox.tsx index 4a50fcfc..7b5411c7 100644 --- a/src/pages/ProjectEditPage/components/TechStacksFields/components/StackSearchBox.tsx +++ b/src/pages/ProjectEditPage/components/TechStacksFields/components/StackSearchBox.tsx @@ -22,9 +22,7 @@ const StackSearchBox = ({ return ( - + + w="100%"> {render({ techStacks })} From 12e6c2d9a87e4fce8caae01b746024ab62e54ddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Wed, 20 Mar 2024 02:08:58 +0900 Subject: [PATCH 15/35] =?UTF-8?q?=20[Feat=20=E2=9C=8F=EF=B8=8F]=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EA=B8=B0=EB=B3=B8=EA=B0=92=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/ProjectEditPage/constants/defaultValues.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/ProjectEditPage/constants/defaultValues.ts b/src/pages/ProjectEditPage/constants/defaultValues.ts index c2cb4045..35ba9d78 100644 --- a/src/pages/ProjectEditPage/constants/defaultValues.ts +++ b/src/pages/ProjectEditPage/constants/defaultValues.ts @@ -10,8 +10,8 @@ export const ProjectFormDefaultValues: ProjectFormValues = { deployUrl: "", startDate: "", endDate: "", - techStacks: [], + techStacks: [{ category: "", data: [] }], description: "", troubleShooting: "", - members: [], + members: [{ category: "", data: [] }], } From 94738d9893f761b3c4db743aa03be43f5d66b2a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Wed, 20 Mar 2024 02:12:54 +0900 Subject: [PATCH 16/35] =?UTF-8?q?=20[Refactoring=20=E2=9A=99=EF=B8=8F]=20?= =?UTF-8?q?=EA=B8=B0=EC=88=A0=EC=8A=A4=ED=83=9D=20=EC=84=A0=ED=83=9D=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=97=90=EB=9F=AC=20=EB=B0=8F=20=EC=9C=A0?= =?UTF-8?q?=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TechStacksFields/TechStackFields.tsx | 123 +++++++++++------- .../hooks/useTechStacksMethods.ts | 16 ++- .../constants/registerOptions.ts | 17 ++- 3 files changed, 102 insertions(+), 54 deletions(-) diff --git a/src/pages/ProjectEditPage/components/TechStacksFields/TechStackFields.tsx b/src/pages/ProjectEditPage/components/TechStacksFields/TechStackFields.tsx index 7920ea4c..f3482f61 100644 --- a/src/pages/ProjectEditPage/components/TechStacksFields/TechStackFields.tsx +++ b/src/pages/ProjectEditPage/components/TechStacksFields/TechStackFields.tsx @@ -1,4 +1,3 @@ -import { Controller } from "react-hook-form" import { MdClose } from "react-icons/md" import { @@ -8,13 +7,14 @@ import { Flex, Image, Input, + Text, } from "@chakra-ui/react" +import { ErrorMessage } from "@components/ErrorMessage/ErrorMessage" import CloseButtonTag from "@components/Tag/components/CloseButtonTag" import CommonTag from "@components/Tag/components/CommonTag" import { useTechStacksMethods } from "@pages/ProjectEditPage/components/TechStacksFields/hooks/useTechStacksMethods" -import { projectInputRegister } from "@pages/ProjectEditPage/constants/registerOptions" import { filterSelectedId } from "@pages/ProjectEditPage/utils/filterSelectedId" import FieldContainer from "../styles/FieldContainer" @@ -24,37 +24,57 @@ import StackSearchBox from "./components/StackSearchBox" const TechStacksFields = () => { const { fields, - control, appendNewFields, removeField, appendStack, selectedStacks, removeStack, register, + errors, + trigger, } = useTechStacksMethods() + register(`techStacks.${0}.data`, { + validate: { + isEmpty: (data) => { + return data.length === 0 && "하나 이상의 기술 스택을 추가해주세요" + }, + }, + }) + return ( -
- - {fields.map((field, index) => { - return ( - - - ( - - )} - /> - + + {fields.map((field, index) => { + return ( + + + + { + return
{message}
+ }} + /> +
+ + {errors?.techStacks && errors.techStacks[index]?.data && ( + { + return {message} + }} + /> + )} { return ( @@ -69,7 +89,12 @@ const TechStacksFields = () => { return ( appendStack(index, techStack)} + onClick={() => { + appendStack(index, techStack) + trigger(`techStacks.${index}.data`, { + shouldFocus: true, + }) + }} key={techStack.name}> { ) }} /> - - {selectedStacks(index).map((stack) => ( - removeStack(index, stack)} - /> - ))} - - removeField(index)}> - - -
- ) - })} - -
-
+
+ + {selectedStacks(index).map((stack) => ( + removeStack(index, stack)} + /> + ))} + + removeField(index)}> + + +
+ ) + })} + +
) } export default TechStacksFields diff --git a/src/pages/ProjectEditPage/components/TechStacksFields/hooks/useTechStacksMethods.ts b/src/pages/ProjectEditPage/components/TechStacksFields/hooks/useTechStacksMethods.ts index 952b07db..1dc4ee50 100644 --- a/src/pages/ProjectEditPage/components/TechStacksFields/hooks/useTechStacksMethods.ts +++ b/src/pages/ProjectEditPage/components/TechStacksFields/hooks/useTechStacksMethods.ts @@ -6,12 +6,22 @@ import { useProjectFormContext } from "@pages/ProjectEditPage/hooks/useProjectFo import { ProjectFormValues } from "@pages/ProjectEditPage/types/ProjectFormValues" export const useTechStacksMethods = () => { - const { control, setValue, getValues, watch, register } = - useProjectFormContext() + const { + control, + setValue, + getValues, + watch, + register, + formState: { errors }, + trigger, + } = useProjectFormContext() const { append, fields, remove } = useFieldArray({ control, name: "techStacks", + rules: { + required: "하나 이상은 필수입니다", + }, }) const appendNewFields = () => { @@ -48,5 +58,7 @@ export const useTechStacksMethods = () => { selectedStacks, removeField, register, + errors, + trigger, } } diff --git a/src/pages/ProjectEditPage/constants/registerOptions.ts b/src/pages/ProjectEditPage/constants/registerOptions.ts index 5ec466b9..5850826a 100644 --- a/src/pages/ProjectEditPage/constants/registerOptions.ts +++ b/src/pages/ProjectEditPage/constants/registerOptions.ts @@ -1,6 +1,10 @@ import { FieldPath, RegisterOptions } from "react-hook-form" -import { ProjectFormValues } from "../types/ProjectFormValues" +import { + ProjectFormValues, + RequestedMemberType, +} from "../types/ProjectFormValues" +import { checkEmptyField } from "../utils/checkEmptyField" const TITLE_MAX_LENGTH = 50 const OVERVIEW_MAX_LENGTH = 300 @@ -29,11 +33,18 @@ export const projectInputRegister: ProjectInputRegisterType = { endDate: { required: "프로젝트 완성 날짜를 입력해주세요" }, - techStacks: { required: "하나 이상은 필수입니다" }, + techStacks: {}, overviewImageUrl: {}, - members: { required: "하나 이상은 필수입니다" }, + members: { + required: "하나 이상은 필수입니다", + validate: { + isEmpty: (data: { category: string; data: RequestedMemberType[] }[]) => + !checkEmptyField(data) || + "멤버를 한명은 넣어주세요", + }, + }, description: {}, From a8aea35756a7f4f89176cb10415f52a42f3f2bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Wed, 20 Mar 2024 02:59:27 +0900 Subject: [PATCH 17/35] =?UTF-8?q?=20[Design=20=F0=9F=8E=A8]=20MemberAvatar?= =?UTF-8?q?Card=EB=A1=9C=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/MemberAvatarCard.tsx | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/pages/ProjectEditPage/components/MemberFields/components/MemberAvatarCard.tsx diff --git a/src/pages/ProjectEditPage/components/MemberFields/components/MemberAvatarCard.tsx b/src/pages/ProjectEditPage/components/MemberFields/components/MemberAvatarCard.tsx new file mode 100644 index 00000000..10b12af5 --- /dev/null +++ b/src/pages/ProjectEditPage/components/MemberFields/components/MemberAvatarCard.tsx @@ -0,0 +1,27 @@ +import { IoCloseCircle } from "react-icons/io5" + +import AvatarCard from "@components/AvatarCard/AvatarCard" + +const MemberAvatarCard = ({ + image, + text, + onClick, +}: { + image: string + text: string + onClick: () => void +}) => { + return ( + + + + + + ) +} + +export default MemberAvatarCard From cd8a38448e529bb6fe49587d89d411052a98124e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Wed, 20 Mar 2024 03:01:48 +0900 Subject: [PATCH 18/35] =?UTF-8?q?=20[Refactoring=20=E2=9A=99=EF=B8=8F]=20U?= =?UTF-8?q?serSearchBox=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MemberFields/components/UserSearchBox.tsx | 54 +++++++++++++------ 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/src/pages/ProjectEditPage/components/MemberFields/components/UserSearchBox.tsx b/src/pages/ProjectEditPage/components/MemberFields/components/UserSearchBox.tsx index e167d3eb..ef2e3d89 100644 --- a/src/pages/ProjectEditPage/components/MemberFields/components/UserSearchBox.tsx +++ b/src/pages/ProjectEditPage/components/MemberFields/components/UserSearchBox.tsx @@ -1,6 +1,14 @@ import { Suspense } from "react" -import { Box, BoxProps, Center, Spinner } from "@chakra-ui/react" +import { + Avatar, + Box, + BoxProps, + Center, + Flex, + Spinner, + Text, +} from "@chakra-ui/react" import { UserSummary } from "api-models" import { useOutsideClick } from "src/components/Search/hooks/useOutsideClick" @@ -9,6 +17,7 @@ import { useInput } from "@components/Search/hooks/useInput" import { filterSelectedId } from "@pages/ProjectEditPage/utils/filterSelectedId" +import SearchResultContainer from "../../styles/SearchResultContainer" import UserListFetcher from "./UserListFetcher" interface UserSearchBoxProps extends Omit { @@ -43,10 +52,9 @@ const UserSearchBox = ({ width="20rem" {...props}> ( - {filterSelectedId(data, selectedMembers)?.map( - ({ id, nickname, profileImageUrl }) => ( - onClick({ id, nickname, profileImageUrl })}> - #{nickname} + + {inputValue && ( + handleClickNonUser(inputValue)}> + {inputValue} 추가하기 - ), - )} - {inputValue && ( - handleClickNonUser(inputValue)}> - {inputValue} 추가하기 - - )} + )} + {filterSelectedId(data, selectedMembers)?.map( + ({ id, nickname, profileImageUrl }, idx) => ( + + onClick({ id, nickname, profileImageUrl }) + }> + + {nickname} + + ), + )} + )} /> From fb896e0119d59261fe37ae2076ad74849a6cc372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Wed, 20 Mar 2024 03:11:31 +0900 Subject: [PATCH 19/35] =?UTF-8?q?=20[Design=20=F0=9F=8E=A8]=20CloseButton?= =?UTF-8?q?=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/styles/CloseButton.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/pages/ProjectEditPage/components/styles/CloseButton.tsx diff --git a/src/pages/ProjectEditPage/components/styles/CloseButton.tsx b/src/pages/ProjectEditPage/components/styles/CloseButton.tsx new file mode 100644 index 00000000..37ec847d --- /dev/null +++ b/src/pages/ProjectEditPage/components/styles/CloseButton.tsx @@ -0,0 +1,18 @@ +import { MdClose } from "react-icons/md" + +import { Box, ButtonProps } from "@chakra-ui/react" + +const CloseButton = ({ ...props }: ButtonProps) => { + return ( + + + + ) +} + +export default CloseButton From 91605cefa47b7497048e86bf2816e6e4db756cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Wed, 20 Mar 2024 03:12:16 +0900 Subject: [PATCH 20/35] =?UTF-8?q?=20[Refactoring=20=E2=9A=99=EF=B8=8F]=20M?= =?UTF-8?q?emberFields=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/MemberFields/MemberFields.tsx | 109 ++++++++++++------ .../hooks/useMemberFieldsMethods.ts | 13 ++- 2 files changed, 86 insertions(+), 36 deletions(-) diff --git a/src/pages/ProjectEditPage/components/MemberFields/MemberFields.tsx b/src/pages/ProjectEditPage/components/MemberFields/MemberFields.tsx index 9884f35c..c8774bfb 100644 --- a/src/pages/ProjectEditPage/components/MemberFields/MemberFields.tsx +++ b/src/pages/ProjectEditPage/components/MemberFields/MemberFields.tsx @@ -1,10 +1,10 @@ -import { IoCloseCircle } from "react-icons/io5" +import { Box, Button, Input, Text } from "@chakra-ui/react" -import { Button, Flex, Input } from "@chakra-ui/react" - -import AvatarCard from "@components/AvatarCard/AvatarCard" +import { ErrorMessage } from "@components/ErrorMessage/ErrorMessage" +import CloseButton from "../styles/CloseButton" import FieldContainer from "../styles/FieldContainer" +import MemberAvatarCard from "./components/MemberAvatarCard" import UserSearchBox from "./components/UserSearchBox" import { useMemberFieldsMethods } from "./hooks/useMemberFieldsMethods" @@ -17,48 +17,89 @@ const MemberFields = () => { appendMembers, removeMembers, getSelectedMembers, + errors, + trigger, } = useMemberFieldsMethods() return ( - + <> {fields.map((field, idx) => { const selectedMembers = getSelectedMembers(idx) + register(`members.${idx}.data`, { + validate: { + isEmpty: (data) => { + return data?.length === 0 && "한명 이상의 멤버를 추가해주세요" + }, + }, + }) + return ( - deleteFields(idx)} - /> - - { - appendMembers({ id, nickname, profileImageUrl }, idx) - }} - selectedMembers={getSelectedMembers(idx)} - /> - {selectedMembers?.map((member, idx) => { - return ( - - removeMembers(member, idx)} + + + { + return ( + + {message} + + ) + }} + /> + + + + { + return ( + + {message} + + ) + }} + /> + { + appendMembers({ id, nickname, profileImageUrl }, idx) + trigger(`members.${idx}.data`) + }} + selectedMembers={getSelectedMembers(idx)} + /> + + + {selectedMembers?.map((member, idx) => { + return ( + { + removeMembers(member, idx) + }} /> - - - - ) - })} + ) + })} + + {idx >= 1 && deleteFields(idx)} />} ) })} - + ) } diff --git a/src/pages/ProjectEditPage/components/MemberFields/hooks/useMemberFieldsMethods.ts b/src/pages/ProjectEditPage/components/MemberFields/hooks/useMemberFieldsMethods.ts index f667deb7..7ec96c21 100644 --- a/src/pages/ProjectEditPage/components/MemberFields/hooks/useMemberFieldsMethods.ts +++ b/src/pages/ProjectEditPage/components/MemberFields/hooks/useMemberFieldsMethods.ts @@ -4,8 +4,15 @@ import { useProjectFormContext } from "@pages/ProjectEditPage/hooks/useProjectFo import { RequestedMemberType } from "@pages/ProjectEditPage/types/ProjectFormValues" export const useMemberFieldsMethods = () => { - const { control, getValues, setValue, watch, register } = - useProjectFormContext() + const { + control, + getValues, + setValue, + watch, + register, + trigger, + formState: { errors }, + } = useProjectFormContext() const { fields, append, remove } = useFieldArray({ name: "members", @@ -48,5 +55,7 @@ export const useMemberFieldsMethods = () => { appendMembers, removeMembers, getSelectedMembers, + errors, + trigger, } } From 933ff9d4c21e74647f3e83656664c0cddebee1f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Wed, 20 Mar 2024 03:12:48 +0900 Subject: [PATCH 21/35] =?UTF-8?q?=20[Design=20=F0=9F=8E=A8]=20cursor=20poi?= =?UTF-8?q?nter=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Search/components/SearchResult.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Search/components/SearchResult.tsx b/src/components/Search/components/SearchResult.tsx index 22d96a51..db739b8c 100644 --- a/src/components/Search/components/SearchResult.tsx +++ b/src/components/Search/components/SearchResult.tsx @@ -22,6 +22,7 @@ const SearchResult = ({ overflow="hidden" zIndex="dropdown" flexDir="column" + cursor="pointer" {...props}> {children} From 02430b8993508f5572326aeca73f65877e808d06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Wed, 20 Mar 2024 03:13:12 +0900 Subject: [PATCH 22/35] =?UTF-8?q?=20[Design=20=F0=9F=8E=A8]=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=83=89=EC=83=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TechStacksFields/TechStackFields.tsx | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/src/pages/ProjectEditPage/components/TechStacksFields/TechStackFields.tsx b/src/pages/ProjectEditPage/components/TechStacksFields/TechStackFields.tsx index f3482f61..0ff4b257 100644 --- a/src/pages/ProjectEditPage/components/TechStacksFields/TechStackFields.tsx +++ b/src/pages/ProjectEditPage/components/TechStacksFields/TechStackFields.tsx @@ -1,5 +1,3 @@ -import { MdClose } from "react-icons/md" - import { AbsoluteCenter, Box, @@ -17,6 +15,7 @@ import CommonTag from "@components/Tag/components/CommonTag" import { useTechStacksMethods } from "@pages/ProjectEditPage/components/TechStacksFields/hooks/useTechStacksMethods" import { filterSelectedId } from "@pages/ProjectEditPage/utils/filterSelectedId" +import CloseButton from "../styles/CloseButton" import FieldContainer from "../styles/FieldContainer" import SearchResultContainer from "../styles/SearchResultContainer" import StackSearchBox from "./components/StackSearchBox" @@ -34,19 +33,21 @@ const TechStacksFields = () => { trigger, } = useTechStacksMethods() - register(`techStacks.${0}.data`, { - validate: { - isEmpty: (data) => { - return data.length === 0 && "하나 이상의 기술 스택을 추가해주세요" - }, - }, - }) - return ( {fields.map((field, index) => { + register(`techStacks.${index}.data`, { + validate: { + isEmpty: (data) => { + return ( + data?.length === 0 && "하나 이상의 기술 스택을 추가해주세요" + ) + }, + }, + }) + return ( @@ -60,7 +61,13 @@ const TechStacksFields = () => { name={`techStacks[${index}].category`} errors={errors} render={({ message }) => { - return
{message}
+ return ( + + {message} + + ) }} />
@@ -71,7 +78,13 @@ const TechStacksFields = () => { name={`techStacks.${index}.data`} errors={errors} render={({ message }) => { - return {message} + return ( + + {message} + + ) }} /> )} @@ -126,14 +139,7 @@ const TechStacksFields = () => { /> ))} - removeField(index)}> - - + {index >= 1 && removeField(index)} />}
) })} From bff53c0079fb5b4b121819e35d45eec17d736687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A9=E1=86=BC=E1=84=92?= =?UTF-8?q?=E1=85=A7=E1=86=A8?= Date: Wed, 20 Mar 2024 03:13:37 +0900 Subject: [PATCH 23/35] =?UTF-8?q?=20[Refactoring=20=E2=9A=99=EF=B8=8F]=20F?= =?UTF-8?q?ield=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=9D=BC?= =?UTF-8?q?=EB=B2=A8=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/ProjectForm.tsx | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/pages/ProjectEditPage/components/ProjectForm.tsx b/src/pages/ProjectEditPage/components/ProjectForm.tsx index ea081ed7..4ba38ce8 100644 --- a/src/pages/ProjectEditPage/components/ProjectForm.tsx +++ b/src/pages/ProjectEditPage/components/ProjectForm.tsx @@ -1,4 +1,4 @@ -import { Box, Button, Flex, Input, Text, Textarea } from "@chakra-ui/react" +import { Box, Button, Flex, FormLabel, Input, Textarea } from "@chakra-ui/react" import ProjectFormProvider from "../stores/ProjectFormProvider" import Description from "./Editors/Description" @@ -34,10 +34,13 @@ const ProjectForm = () => { + label="요약" + footer="최대 150자까지 작성 가능합니다">