From 5f0e72c5210772559fbdefee53911a2bc31a122c 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: Mon, 25 Mar 2024 00:44:54 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=20[Feat=20=E2=9C=8F=EF=B8=8F]=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=20registerOptions=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../constants/registerOptions.ts | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/pages/ProjectEditPage/constants/registerOptions.ts b/src/pages/ProjectEditPage/constants/registerOptions.ts index 2ca51bb4..e2bf4b86 100644 --- a/src/pages/ProjectEditPage/constants/registerOptions.ts +++ b/src/pages/ProjectEditPage/constants/registerOptions.ts @@ -1,7 +1,11 @@ import { RegisterOptions } from "react-hook-form" +import { useTechStackStore } from "@stores/useTechStackStore" + import { URL_REGEX } from "@constants/regExp" +import { useMemberStore } from "../components/MemberFields/stores/useMemberStore" + const TITLE_MAX_LENGTH = 50 const OVERVIEW_MAX_LENGTH = 300 @@ -64,4 +68,33 @@ export const projectInputRegister: ProjectInputRegisterType = { message: "유효한 URL 형식이 아닙니다", }, }, + + members: { + validate: () => { + const { fields } = useMemberStore.getState() + const isMemberFieldsValid = fields.every((field) => { + const isRoleValid = field.role && field.role.trim().length > 0 + const isCategoryValid = + Array.isArray(field.userSummary) && field.userSummary.length > 0 + return isRoleValid && isCategoryValid + }) + return isMemberFieldsValid || "분야와 함께 작업한 팀원을 추가해주세요" + }, + }, + + techStacks: { + validate: () => { + const { fields } = useTechStackStore.getState() + const isMemberFieldsValid = fields.every((field) => { + const isRoleValid = field.category && field.category.trim().length > 0 + const isCategoryValid = + Array.isArray(field.skill) && field.skill.length > 0 + return isRoleValid && isCategoryValid + }) + return ( + isMemberFieldsValid || + "기술 스택 분야와 함께 한개 이상의 기술스택을 선택해주세요" + ) + }, + }, } From 1415ed343b92848ca80780d7138cd16f7f44f2ff 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: Mon, 25 Mar 2024 00:45:29 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=20[Feat=20=E2=9C=8F=EF=B8=8F]=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=EC=97=90=20=EB=8C=80=ED=95=9C=20=EC=97=90=EB=9F=AC?= =?UTF-8?q?=EB=A9=94=EC=8B=9C=EC=A7=80=20=EB=B0=8F=20=EC=9C=A0=ED=9A=A8?= =?UTF-8?q?=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 --- .../components/Files/Overview.tsx | 4 ++- .../components/MemberFields/MemberFields.tsx | 35 +++++++++++++++++-- .../components/ProjectForm.tsx | 11 +++--- .../TechStacksFields/TechStackFields.tsx | 35 +++++++++++++++++-- .../components/styles/FieldContainer.tsx | 35 +++++++++++-------- .../stores/ProjectFormProvider.tsx | 5 ++- 6 files changed, 94 insertions(+), 31 deletions(-) diff --git a/src/pages/ProjectEditPage/components/Files/Overview.tsx b/src/pages/ProjectEditPage/components/Files/Overview.tsx index eebd4882..0fe4ab65 100644 --- a/src/pages/ProjectEditPage/components/Files/Overview.tsx +++ b/src/pages/ProjectEditPage/components/Files/Overview.tsx @@ -54,7 +54,9 @@ const Overview = () => { /> ) : ( onDropFile(e, idx)} + onDrop={(e) => { + onDropFile(e, idx) + }} multiple={false} accept={{ "image/*": [".jpeg", ".png"] }}> {(inputProps) => ( diff --git a/src/pages/ProjectEditPage/components/MemberFields/MemberFields.tsx b/src/pages/ProjectEditPage/components/MemberFields/MemberFields.tsx index aaef475f..7687ae34 100644 --- a/src/pages/ProjectEditPage/components/MemberFields/MemberFields.tsx +++ b/src/pages/ProjectEditPage/components/MemberFields/MemberFields.tsx @@ -1,8 +1,14 @@ -import { useState } from "react" +import { useEffect, useRef, useState } from "react" import { Box, Button, Flex, Input } from "@chakra-ui/react" +import { ErrorMessage } from "@components/ErrorMessage/ErrorMessage" + +import { projectInputRegister } from "@pages/ProjectEditPage/constants/registerOptions" +import { useProjectFormContext } from "@pages/ProjectEditPage/hooks/useProjectFormContext" + import CloseButton from "../styles/CloseButton" +import ErrorText from "../styles/ErrorText" import FieldContainer from "../styles/FieldContainer" import MemberAvatarCard from "./components/MemberAvatarCard" import UserSearchBox from "./components/UserSearchBox" @@ -18,26 +24,49 @@ const MemberFields = () => { changeRole, } = useMemberStore() + const { + formState: { errors }, + register, + } = useProjectFormContext() + const [max, setMax] = useState(0) const MAX_FIELDS_NUMBER = 4 const MIN_FIELDS_NUMBER = 1 + const ref = useRef(null) + + useEffect(() => { + register("members", projectInputRegister["members"]) + }, [register]) + + useEffect(() => { + if (errors.members) { + ref.current?.focus() + } + }, [errors.members]) + return ( + } + /> {fields?.map((field, fieldIdx) => { return ( + overflow="scroll" + ref={ref} + tabIndex={-1}> changeRole(e.target.value.trim(), fieldIdx)} - required={true} value={field.role} /> diff --git a/src/pages/ProjectEditPage/components/ProjectForm.tsx b/src/pages/ProjectEditPage/components/ProjectForm.tsx index c3bba62c..35f27d47 100644 --- a/src/pages/ProjectEditPage/components/ProjectForm.tsx +++ b/src/pages/ProjectEditPage/components/ProjectForm.tsx @@ -4,7 +4,6 @@ import { FormControl, FormHelperText, FormLabel, - Grid, Input, Text, Textarea, @@ -24,12 +23,12 @@ const ProjectForm = () => { flexDir="column" gap="30px"> - + + - + { deleteStack, changeCategory, } = useTechStackStore() + + const { + formState: { errors }, + register, + } = useProjectFormContext() + + const ref = useRef(null) + const [max, setMax] = useState(0) const [MAX_FIELDS_NUMBER, MIN_FIELDS_NUMBER] = [4, 1] + useEffect(() => { + register("techStacks", projectInputRegister["techStacks"]) + }, [register]) + + useEffect(() => { + if (errors.techStacks) { + ref.current?.focus() + } + }, [errors.techStacks]) + return ( + } + /> {fields?.map((field, index) => { return ( + gap="5px" + ref={ref} + tabIndex={-1}> changeCategory(e.target.value, index)} /> diff --git a/src/pages/ProjectEditPage/components/styles/FieldContainer.tsx b/src/pages/ProjectEditPage/components/styles/FieldContainer.tsx index aa73a496..83a65ffa 100644 --- a/src/pages/ProjectEditPage/components/styles/FieldContainer.tsx +++ b/src/pages/ProjectEditPage/components/styles/FieldContainer.tsx @@ -1,21 +1,26 @@ -import { PropsWithChildren } from "react" +import React, { ForwardedRef, PropsWithChildren } from "react" import { Flex, FlexProps } from "@chakra-ui/react" -const FieldContainer = ({ - children, - ...props -}: PropsWithChildren) => ( - - {children} - +const FieldContainer = React.forwardRef( + ( + { children, ...props }: PropsWithChildren, + ref: ForwardedRef, + ) => ( + + {children} + + ), ) +FieldContainer.displayName = "FieldContainer" + export default FieldContainer diff --git a/src/pages/ProjectEditPage/stores/ProjectFormProvider.tsx b/src/pages/ProjectEditPage/stores/ProjectFormProvider.tsx index 6c6729f9..3d536db5 100644 --- a/src/pages/ProjectEditPage/stores/ProjectFormProvider.tsx +++ b/src/pages/ProjectEditPage/stores/ProjectFormProvider.tsx @@ -47,9 +47,6 @@ const ProjectFormProvider = ({ }) }, onSuccess: (data) => { - queryClient.invalidateQueries({ - queryKey: [QUERYKEY.PROJECT_DETAIL], - }) navigate(`../project/${data.id}`) }, }) @@ -71,11 +68,13 @@ const ProjectFormProvider = ({ const handleSubmitEvent = (data: ProjectFormValues) => { const convertedData = { ...data, + overviewImageUrl: data.overviewImageUrl.filter((url) => url), techStacks: convertTechStacksData(useTechStackStore.getState().fields), members: convertMembersData(useMemberStore.getState().fields), startDate: convertDate(data.startDate), endDate: convertDate(data.endDate), } + if (!projectId) { postProject({ ...convertedData,