Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions src/features/study/group/model/group-study-form.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,33 @@ export type StudyClassification = (typeof STUDY_CLASSIFICATION)[number];

export const GroupStudyFormSchema = z.object({
classification: z.enum(STUDY_CLASSIFICATION),
// 스터디 유형(1)
type: z.enum(STUDY_TYPES),
// 모집 대상(1)
targetRoles: z
.array(z.enum(TARGET_ROLE_OPTIONS))
.min(1, '역할을 1개 이상 선택해 주세요.'),
// 모집 인원(1)
maxMembersCount: z
.string()
.trim()
.regex(/^[1-9]\d*$/, '최소 1명 이상을 선택해주세요.'),
// 경력 여부(1)
experienceLevels: z
.array(z.enum(EXPERIENCE_LEVEL_OPTIONS))
.min(1, '경력을 1개 이상 선택해 주세요.'),
// 진행 방식(1)
method: z.enum(STUDY_METHODS),
// 진행 방식 (위치) optional (1)
location: z.string().trim(),
// 정기 모임(1)
regularMeeting: z.enum(REGULAR_MEETINGS),
// 진행 기간 (시작일) (1)
startDate: z
.string()
.trim()
.regex(ISO_DATE_REGEX, 'YYYY-MM-DD 형식의 시작일을 입력해 주세요.'),
// 진행 시간 (종료일) (1)
endDate: z
.string()
.trim()
Expand All @@ -46,9 +55,20 @@ export const GroupStudyFormSchema = z.object({
(val) => !val || Number(val) >= 10000,
'참가비는 10,000원 이상이어야 합니다.',
),
// 스터디 제목(2)
title: z.string().trim().min(1, '스터디 제목을 입력해주세요.'),
// 스터디 한 줄 소개(2)
summary: z.string().trim().min(1, '한 줄 소개를 입력해주세요.'),
// 스터디 소개(2)
description: z.string().trim().min(1, '스터디 소개를 입력해주세요.'),
// 썸네일 START(2)
thumbnailExtension: z
.enum(THUMBNAIL_EXTENSION)
.refine((val) => val !== 'DEFAULT', '썸네일 이미지를 선택해주세요.'),
thumbnailFile: z.instanceof(File).nullable().optional(),
thumbnailUrl: z.string().nullable().optional(),
// 썸네일 END(2)
// 스터디원에게 보여줄 질문을 입력하세요(3)
interviewPost: z
.array(z.string())
.refine((arr) => arr.length > 0 && arr.every((v) => v.trim() !== ''), {
Expand All @@ -57,11 +77,6 @@ export const GroupStudyFormSchema = z.object({
.refine((arr) => arr.length <= 10, {
message: '질문은 최대 10개까지만 입력할 수 있습니다.',
}),
thumbnailExtension: z
.enum(THUMBNAIL_EXTENSION)
.refine((val) => val !== 'DEFAULT', '썸네일 이미지를 선택해주세요.'),
thumbnailFile: z.instanceof(File).nullable().optional(),
thumbnailUrl: z.string().nullable().optional(),
});

// 사진 상태 저장을 위한 로컬용 state
Expand Down
45 changes: 44 additions & 1 deletion src/features/study/group/ui/group-study-form.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { zodResolver } from '@hookform/resolvers/zod';
import { createContext, useContext, useState } from 'react';
import { createContext, useContext, useMemo, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import Button from '@/components/ui/button';
import { Modal } from '@/components/ui/modal';
Expand Down Expand Up @@ -68,6 +68,48 @@ export default function GroupStudyForm({
if (step > 1) setStep((s) => (s - 1) as 1 | 2 | 3);
};

const currentValues = watch();

const isNextButtonDisabled = useMemo(() => {
const currentStepFields = STEP_FIELDS[step];

return currentStepFields.some((field) => {
const value = currentValues[field];
const error = formState.errors[field];

// 에러가 있으면 비활성화
if (error) return true;

// 필수 필드가 비어있으면 비활성화
if (field === 'targetRoles' || field === 'experienceLevels') {
return !value || (Array.isArray(value) && value.length === 0);
}
if (
field === 'maxMembersCount' ||
field === 'startDate' ||
field === 'endDate' ||
field === 'title' ||
field === 'summary' ||
field === 'description'
) {
return !value || (typeof value === 'string' && value.trim() === '');
}
if (field === 'thumbnailExtension') {
return !value || value === 'DEFAULT';
}
if (field === 'interviewPost') {
return (
!value ||
!Array.isArray(value) ||
value.length === 0 ||
value.some((q) => !q || q.trim() === '')
);
}

return false;
});
}, [step, currentValues, formState.errors]);

return (
<ClassificationContext.Provider value={classification}>
<Modal.Body className="flex flex-col gap-150">
Expand Down Expand Up @@ -113,6 +155,7 @@ export default function GroupStudyForm({
color="primary"
type="button"
onClick={goNext}
disabled={isNextButtonDisabled}
>
다음
</Button>
Expand Down
Loading