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
26 changes: 3 additions & 23 deletions src/api/service/group-service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,30 +39,10 @@ export const groupServiceRemote = () => ({
},

// 모임 이미지 사전 업로드 (POST /groups/images/upload) - multipart/form-data
uploadGroupImages: async (
payload: PreUploadGroupImagePayload,
): Promise<PreUploadGroupImageResponse> => {
const formData = new FormData();
payload.images.forEach((file) => {
if (file instanceof File) {
formData.append('images', file);
} else {
console.error('[이미지 업로드 오류] File 객체가 아닌 값이 포함됨:', file);
throw new Error('이미지 파일은 File 객체여야 합니다.');
}
uploadGroupImages: (payload: PreUploadGroupImagePayload) => {
return api.post<PreUploadGroupImageResponse>('/groups/images/upload', payload, {
headers: { 'Content-Type': 'multipart/form-data' },
});

const response = await api.post<PreUploadGroupImageResponse>(
'/groups/images/upload',
formData,
{
headers: {
'Content-Type': 'multipart/form-data',
},
},
);

return response;
},

createGroup: (payload: CreateGroupPayload) => {
Expand Down
49 changes: 9 additions & 40 deletions src/app/post-meetup/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use client';

import { useRouter } from 'next/navigation';

import { useForm } from '@tanstack/react-form';

import {
Expand All @@ -12,14 +14,13 @@ import {
MeetupTagsField,
MeetupTitleField,
} from '@/components/pages/post-meetup';
import { ImageRecord } from '@/components/ui';
import { useCreateGroup } from '@/hooks/use-group/use-group-create';
import { useUploadGroupImages } from '@/hooks/use-group/use-upload-group-images';
import { CreateGroupPayload } from '@/types/service/group';

const PostMeetupPage = () => {
const { replace } = useRouter();

const { mutateAsync: createGroup } = useCreateGroup();
const { mutateAsync: uploadImages } = useUploadGroupImages();

const form = useForm({
defaultValues: {
Expand All @@ -28,46 +29,14 @@ const PostMeetupPage = () => {
locationDetail: '',
startTime: '',
endTime: '',
tags: [] as string[],
tags: [],
description: '',
maxParticipants: 0,
images: {} as ImageRecord,
},
images: [],
} as CreateGroupPayload,
onSubmit: async ({ value }) => {
const imageRecords = value.images as ImageRecord;
const imageFiles = Object.values(imageRecords).filter(
(file): file is File => file !== null && file instanceof File,
);

// 이미지가 있으면 먼저 업로드하여 URL 배열 수확
let uploadedImages = null;
if (imageFiles.length > 0) {
const uploadResponse = await uploadImages({ images: imageFiles });
uploadedImages = uploadResponse.images;
}

if (!value.startTime) {
throw new Error('모임 시작 시간을 입력해주세요.');
}

const maxParticipantsNumber = Number(value.maxParticipants);
if (isNaN(maxParticipantsNumber) || maxParticipantsNumber < 1) {
throw new Error('모임 최대 인원은 1명 이상이어야 합니다.');
}

const createPayload: CreateGroupPayload = {
title: value.title.trim(),
location: value.location.trim(),
locationDetail: value.locationDetail?.trim() || null,
startTime: value.startTime,
...(value.endTime && { endTime: value.endTime }),
tags: value.tags && value.tags.length > 0 ? value.tags : null,
description: value.description.trim(),
maxParticipants: maxParticipantsNumber,
images: uploadedImages && uploadedImages.length > 0 ? uploadedImages : null,
};

await createGroup(createPayload);
const res = await createGroup(value);
replace(`/meetup/${res.id}`);
},
});

Expand Down
3 changes: 0 additions & 3 deletions src/components/pages/meetup/meetup-modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,15 @@ const MODAL_MESSAGE = {
title: '모임에 참여하시겠어요?',
description: '참여 후 바로 그룹채팅에 참여할 수 있어요!',
confirm: '참여하기',
onConfirm: (attendMutate: () => void) => attendMutate(),
},
cancel: {
title: '모임을 정말 탈퇴하시겠어요?',
description: '탈퇴 시 그룹채팅과 모임 활동이 종료돼요.',
confirm: '탈퇴하기',
onConfirm: (cancelMutate: () => void) => cancelMutate(),
},
delete: {
title: '모임을 정말 취소하시겠어요?',
description: '취소 후에는 다시 복구할 수 없어요.',
confirm: '취소하기',
onConfirm: (deleteMutate: () => void) => deleteMutate(),
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ import { Icon } from '@/components/icon';
import { ImageInput, ImageInputProps } from '@/components/ui';
import { cn } from '@/lib/utils';

type ImageUploadPropsWithoutChildren = Omit<ImageInputProps, 'children'>;

interface Props extends ImageUploadPropsWithoutChildren {
interface Props {
field: AnyFieldApi;
initialImages?: ImageInputProps['initialImages'];
}

export const MeetupImagesField = ({ field, initialImages }: Props) => {
Expand Down Expand Up @@ -62,6 +61,7 @@ export const MeetupImagesField = ({ field, initialImages }: Props) => {
'transition-all duration-300', // animation 스타일
)}
aria-label='이미지 삭제 버튼'
type='button'
onClick={() => onRemoveImageClick(url)}
>
<Icon id='small-x-1' className='size-1.5 text-gray-700' />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ import clsx from 'clsx';

import { Icon } from '@/components/icon';
import { Calendar } from '@/components/pages/post-meetup/modals/date-picker-modal/calendar';
import { ModalContent, ModalTitle } from '@/components/ui';
import { Button, ModalContent, ModalTitle, useModal } from '@/components/ui';

interface Props {
dateField: AnyFieldApi;
}

export const DatePickerModal = ({ dateField }: Props) => {
const { close } = useModal();
const [tabMenu, setTabMenu] = useState<'date' | 'time'>('date');

return (
Expand Down Expand Up @@ -45,17 +46,10 @@ export const DatePickerModal = ({ dateField }: Props) => {
updateDateField={(selectedDate: string) => dateField.handleChange(selectedDate)}
/>

<div className='flex-center mt-5 gap-2'>
<button
className='text-text-md-semibold grow-1 rounded-2xl border-1 border-gray-400 bg-white py-3.25 text-gray-600'
type='button'
onClick={close}
>
취소
</button>
<button className='text-text-md-bold bg-mint-400 grow-1 rounded-2xl py-3.5 text-white disabled:bg-gray-500'>
<div className='mt-5'>
<Button className='text-text-md-bold bg-mint-400' onClick={close}>
확인
</button>
</Button>
</div>
</section>
</ModalContent>
Expand Down
1 change: 0 additions & 1 deletion src/hooks/use-group/use-group-create/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export const useCreateGroup = () => {
const query = useMutation({
mutationFn: (payload: CreateGroupPayload) => API.groupService.createGroup(payload),
onSuccess: () => {
// 상세 페이지 이동할거라 목록 캐시를 갱신할 이유가 없음 (GPT 피셜)
console.log('모임 생성 성공.');
},
onError: () => {
Expand Down
12 changes: 0 additions & 12 deletions src/hooks/use-group/use-upload-group-images/index.ts

This file was deleted.