diff --git a/src/app/meetup/[groupId]/page.tsx b/src/app/meetup/[groupId]/page.tsx
index a8601bc4..b2e4d5e2 100644
--- a/src/app/meetup/[groupId]/page.tsx
+++ b/src/app/meetup/[groupId]/page.tsx
@@ -59,7 +59,7 @@ const MeetupDetailPage = ({ params }: Props) => {
isHost,
isJoined,
isPast,
- isAttendDisabled: participantCount >= maxParticipants,
+ isAttendDisabled: participantCount >= maxParticipants || isPast,
}}
groupId={groupId}
/>
diff --git a/src/app/post-meetup/page.tsx b/src/app/post-meetup/page.tsx
index 59ac31cc..5e391a57 100644
--- a/src/app/post-meetup/page.tsx
+++ b/src/app/post-meetup/page.tsx
@@ -2,7 +2,7 @@
import { useRouter } from 'next/navigation';
-import { useForm, useStore } from '@tanstack/react-form';
+import { useForm } from '@tanstack/react-form';
import {
MeetupCapField,
@@ -15,7 +15,8 @@ import {
MeetupTitleField,
} from '@/components/pages/post-meetup';
import { useCreateGroup } from '@/hooks/use-group/use-group-create';
-import { CreateGroupPayload, PreUploadGroupImageResponse } from '@/types/service/group';
+import { CreateGroupFormValues, createGroupSchema } from '@/lib/schema/group';
+import { PreUploadGroupImageResponse } from '@/types/service/group';
const PostMeetupPage = () => {
const { replace } = useRouter();
@@ -26,15 +27,18 @@ const PostMeetupPage = () => {
defaultValues: {
title: '',
location: '',
- locationDetail: '',
startTime: '',
- endTime: '',
tags: [],
description: '',
maxParticipants: 0,
images: [],
- } as CreateGroupPayload,
+ } as CreateGroupFormValues,
+ validators: {
+ onSubmit: createGroupSchema,
+ },
onSubmit: async ({ value }) => {
+ console.log(value);
+
const images = [] as PreUploadGroupImageResponse['images'];
if (value.images) {
@@ -51,10 +55,6 @@ const PostMeetupPage = () => {
},
});
- const values = useStore(form.store, (state) => state.values);
-
- console.log(values);
-
return (
} name='tags' />
- form.handleSubmit()} />
+ {
+ console.log(form.state.fieldMeta.maxParticipants?.isValid);
+
+ form.handleSubmit();
+ }}
+ />
);
diff --git a/src/components/pages/meetup/meetup-buttons/index.tsx b/src/components/pages/meetup/meetup-buttons/index.tsx
index 7aa073b5..6aa0014c 100644
--- a/src/components/pages/meetup/meetup-buttons/index.tsx
+++ b/src/components/pages/meetup/meetup-buttons/index.tsx
@@ -49,7 +49,7 @@ export const MeetupButtons = ({
) : (
+ {isInvalid && }
);
};
diff --git a/src/components/pages/post-meetup/fields/detail-feild/index.tsx b/src/components/pages/post-meetup/fields/detail-feild/index.tsx
index 4e66cc4f..a92f41cc 100644
--- a/src/components/pages/post-meetup/fields/detail-feild/index.tsx
+++ b/src/components/pages/post-meetup/fields/detail-feild/index.tsx
@@ -2,13 +2,15 @@
import { AnyFieldApi } from '@tanstack/react-form';
-import { Label } from '@/components/ui';
+import { Hint, Label } from '@/components/ui';
interface Props {
field: AnyFieldApi;
}
export const MeetupDetailField = ({ field }: Props) => {
+ const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid;
+
return (
);
};
diff --git a/src/components/pages/post-meetup/fields/location-field/index.tsx b/src/components/pages/post-meetup/fields/location-field/index.tsx
index c8505e11..93879c1c 100644
--- a/src/components/pages/post-meetup/fields/location-field/index.tsx
+++ b/src/components/pages/post-meetup/fields/location-field/index.tsx
@@ -5,7 +5,7 @@ import clsx from 'clsx';
import { Icon } from '@/components/icon';
import { LocationSearchModal } from '@/components/pages/post-meetup/modals/location-search-modal';
-import { Label } from '@/components/ui';
+import { Hint, Label } from '@/components/ui';
import { useModal } from '@/components/ui';
interface Props {
@@ -19,6 +19,8 @@ export const MeetupLocationField = ({ field }: Props) => {
open();
};
+ const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid;
+
return (
);
};
diff --git a/src/components/pages/post-meetup/fields/title-field/index.tsx b/src/components/pages/post-meetup/fields/title-field/index.tsx
index 8c53ce4e..e490c991 100644
--- a/src/components/pages/post-meetup/fields/title-field/index.tsx
+++ b/src/components/pages/post-meetup/fields/title-field/index.tsx
@@ -3,13 +3,15 @@
import { AnyFieldApi } from '@tanstack/react-form';
import { Icon } from '@/components/icon';
-import { Input, Label } from '@/components/ui';
+import { Hint, Input, Label } from '@/components/ui';
interface Props {
field: AnyFieldApi;
}
export const MeetupTitleField = ({ field }: Props) => {
+ const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid;
+
return (
);
};
diff --git a/src/lib/schema/group.ts b/src/lib/schema/group.ts
new file mode 100644
index 00000000..b395848b
--- /dev/null
+++ b/src/lib/schema/group.ts
@@ -0,0 +1,24 @@
+import { z } from 'zod';
+
+export const createGroupSchema = z.object({
+ title: z
+ .string()
+ .min(2, '제목은 2자 이상 입력해주세요.')
+ .max(50, '제목은 50자 이내 입력해주세요.'),
+ location: z.string().nonempty('모임 장소를 입력해주세요.'),
+ startTime: z.string().nonempty('날짜와 시간을 입력해주세요.'),
+ tags: z.array(z.string()).optional(),
+ description: z.string().nonempty('상세 정보를 입력해주세요.'),
+ maxParticipants: z.number({ error: '' }).min(2, '최대 인원을 입력해주세요.').max(12),
+ images: z
+ .array(
+ z.object({
+ sortOrder: z.number(),
+ imageUrl440x240: z.string(),
+ imageUrl100x100: z.string(),
+ }),
+ )
+ .optional(),
+});
+
+export type CreateGroupFormValues = z.infer;