diff --git a/apps/cs/src/pages/survey/model/survey-interface.ts b/apps/cs/src/pages/survey/model/survey-interface.ts index 8a4c0e61a..ee1f082cb 100644 --- a/apps/cs/src/pages/survey/model/survey-interface.ts +++ b/apps/cs/src/pages/survey/model/survey-interface.ts @@ -92,18 +92,23 @@ export const articleSchema = z.object({ export const userSurveyFormSchema = z.object({ srvySn: z.number(), rspdnts: z.object({ - rspdntNm: z.string(), - gndrCd: z.string(), - crTypeCd: z.string(), - brdt: z.string(), + rspdntNm: z.string().min(1), + gndrCd: z.string().min(1), + crTypeCd: z.string().min(1), + brdt: z.string().min(8), }), rspnsRslts: z.array( - z.object({ - srvyQitemNo: z.number(), - qstnTypeCd: z.string(), - ansCn: z.string(), - etcAnsCn: z.string(), - }), + z + .object({ + srvyQitemNo: z.number(), + qstnTypeCd: z.string(), + ansCn: z.string(), + etcAnsCn: z.string(), + }) + .refine( + (data) => + data.etcAnsCn.trim().length > 0 || data.ansCn.trim().length > 0, + ), ), }); diff --git a/apps/cs/src/pages/survey/ui/user-survey-article.tsx b/apps/cs/src/pages/survey/ui/user-survey-article.tsx index 66f84c2cb..218e32ceb 100644 --- a/apps/cs/src/pages/survey/ui/user-survey-article.tsx +++ b/apps/cs/src/pages/survey/ui/user-survey-article.tsx @@ -1,12 +1,19 @@ "use client"; -import { useForm, type Control } from "react-hook-form"; +import dayjs from "dayjs"; +import { useState } from "react"; +import { + useForm, + useWatch, + type Control, + type UseFormReturn, +} from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { useMutation, useQuery } from "@tanstack/react-query"; import { + cn, Button, Checkbox, - DatePicker, Input, Label, RadioGroup, @@ -16,18 +23,19 @@ import { import { CodeSelect } from "@/entities/code"; import { useAlertStore } from "@/shared/lib"; import { ENDPOINT } from "@/shared/config"; +import { Form, FormControl, FormField, FormItem } from "@/shared/ui/form"; import { SurveyApi } from "../api/survey-service"; import { userSurveyFormSchema, type Article, type UserSurveyFormData, } from "../model/survey-interface"; -import dayjs from "dayjs"; -import { Form, FormControl, FormField, FormItem } from "@/shared/ui/form"; function UserSurveyArticle({ srvySn }: { srvySn: string }) { const alert = useAlertStore((state) => state.setMessage); + const [brdt, setBrdt] = useState(""); + const { data: userSurvey } = useQuery({ queryKey: [ENDPOINT.CMS_SERVICE.SURVEY, srvySn], queryFn: () => SurveyApi.getUserSurvey(parseInt(srvySn)), @@ -60,8 +68,20 @@ function UserSurveyArticle({ srvySn }: { srvySn: string }) { }, }); + const { success } = userSurveyFormSchema.safeParse(form.getValues()); + const onSubmit = (data: UserSurveyFormData) => { - saveUserSurvey(data); + const updatedData = { + ...data, + rspnsRslts: data.rspnsRslts.map((field) => { + if (field.qstnTypeCd === "RADIO" && field.ansCn === "0") { + return { ...field, ansCn: "" }; + } + return field; + }), + }; + + saveUserSurvey(updatedData); }; return ( @@ -74,7 +94,9 @@ function UserSurveyArticle({ srvySn }: { srvySn: string }) { {userSurvey?.srvyTtl}
- +
))} @@ -266,13 +309,13 @@ function RadioArticle({ } function CheckArticle({ - control, + form, qstnCn, index: i, maxChcCnt, articles, }: { - control: Control; + form: UseFormReturn; index: number; qstnCn: string; maxChcCnt: number; @@ -280,50 +323,74 @@ function CheckArticle({ }) { const alert = useAlertStore((state) => state.setMessage); + const selectedValues = useWatch({ + control: form.control, + name: `rspnsRslts.${i}.ansCn`, + }); + + const filteredValues = + selectedValues?.split(",").filter((v) => v.trim() !== "") || []; + + const [isEtcChecked, setIsEtcChecked] = useState(false); + + const handleCheckedChange = (value: string) => (checked: boolean) => { + const values = filteredValues; + + if (checked) { + values.push(value); + } else { + const valueIndex = values.indexOf(value); + if (valueIndex !== -1) values.splice(valueIndex, 1); + } + + form.setValue(`rspnsRslts.${i}.ansCn`, values.join(",")); + }; + + const validMaxCheckedCount = () => { + let checkedCount = 0; + if (isEtcChecked) checkedCount += 1; + checkedCount += filteredValues.length; + return checkedCount < maxChcCnt; + }; + return (

{qstnCn} (최대 {maxChcCnt}개 선택)

{ - const selectedValues = field.value?.split(",") || []; - const handleCheckedChange = (value: string) => (checked: boolean) => { - const values = [...selectedValues]; - - if (checked) { - if (values.length >= maxChcCnt) { - alert("최대 선택 개수를 초과했습니다."); - return; - } - values.push(value); - } else { - const valueIndex = values.indexOf(value); - if (valueIndex !== -1) { - values.splice(valueIndex, 1); - } - } - - field.onChange(values.filter((v) => v.trim() !== "").join(",")); - }; - - return ( - - -
- {articles.map((article, j) => { - const value = article.srvyArtclNo?.toString() ?? ""; - return ( -
+ render={() => ( + + +
+ {articles.map((article, j) => { + const srvyArtclNo = article.srvyArtclNo?.toString() ?? ""; + return ( +
+
{ + if (checked && !validMaxCheckedCount()) { + alert("최대 선택 개수를 초과했습니다."); + return; + } + if (article.srvyArtclNo === 0) { + setIsEtcChecked(checked); + } else { + handleCheckedChange(srvyArtclNo)(checked); + } + }} />
- ); - })} -
- - - ); - }} + {article.srvyArtclNo === 0 && ( + ( + + )} + /> + )} +
+ ); + })} +
+ + + )} />
);