Skip to content

Commit

Permalink
Merge pull request #86 from School-of-Company/fix/create-form
Browse files Browse the repository at this point in the history
🐛 폼 생성 제출 이슈
  • Loading branch information
Ethen1264 authored Jan 30, 2025
2 parents 9a570f5 + 3c66fec commit 7783c37
Show file tree
Hide file tree
Showing 13 changed files with 76 additions and 89 deletions.
5 changes: 4 additions & 1 deletion src/app/api/form/[expo_id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ export async function POST(
: {};
try {
const response = await apiClient.post(`/form/${expo_id}`, body, config);
return NextResponse.json(response.data);
return new NextResponse(JSON.stringify(response.data), {
status: response.status,
headers: { 'Content-Type': 'application/json' },
});
} catch (error) {
const axiosError = error as AxiosError<{ message: string }>;

Expand Down
1 change: 0 additions & 1 deletion src/entities/create-form/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@ export { default as FormTypeSelect } from './ui/FormTypeSelect';
export { default as MultipleChoiceOption } from './ui/MultipleChoiceOption';
export { default as PictureOption } from './ui/PictureOption';
export { default as RequiredToggle } from './ui/RequiredToggle';
export { default as TextOption } from './ui/TextOption';
export { default as CreateFormButton } from './ui/CreateFormButton';
export { default as CheckBox } from './ui/CheckBox';
4 changes: 3 additions & 1 deletion src/entities/create-form/ui/FormTitle/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ const FormTitle = ({ register, index }: Props) => {
return (
<div className="w-[60%] border-b-1 border-solid border-gray-100 py-4">
<input
{...register(`questions.${index}.title`)}
{...register(`questions.${index}.title`, {
required: `${index + 1}번 폼의 제목을 입력해주세요`,
})}
placeholder="제목 입력"
className="w-full text-h4 text-black"
/>
Expand Down
2 changes: 1 addition & 1 deletion src/entities/create-form/ui/OptionItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const OptionItem = ({
<div className="flex w-full items-center gap-[10px]">
{icon}
<input
{...register(inputName)}
{...register(inputName, { required: '폼의 옵션을 입력해주세요' })}
placeholder="문장을 입력해주세요."
className="w-[60%] text-body4 text-black"
/>
Expand Down
30 changes: 0 additions & 30 deletions src/entities/create-form/ui/TextOption/index.tsx

This file was deleted.

10 changes: 10 additions & 0 deletions src/shared/types/create-form/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,13 @@ export interface OptionProps {
index: number;
isCheckBox?: boolean;
}

export interface CreateFormRequest {
informationImage: string;
participantType: string;
dynamicForm: {
title: string;
formType: string;
jsonData: string;
}[];
}
6 changes: 3 additions & 3 deletions src/shared/ui/ToggleButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ function ToggleButton() {
return (
<button
onClick={toggle}
className={`relative inline-flex h-6 w-12 items-center rounded-full bg-gray-100 transition-colors`}
className={`relative inline-flex h-6 w-12 items-center rounded-full transition-colors ${isToggled ? 'bg-main-100' : 'bg-gray-100'}`}
>
<span
className={`inline-block h-7 w-7 transform rounded-full bg-gray-500 transition-transform duration-300 ${
isToggled ? 'translate-x-9' : 'translate-x-0'
className={`inline-block h-7 w-7 transform rounded-full transition-transform duration-300 ${
isToggled ? 'translate-x-9 bg-main-600' : 'translate-x-0 bg-gray-500'
}`}
/>
</button>
Expand Down
11 changes: 2 additions & 9 deletions src/views/create-form/api/createForm.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
import axios from 'axios';
import { CreateFormRequest } from '@/shared/types/create-form/type';

export const createForm = async ({
data,
id,
}: {
data: {
informationImage: string;
participantType: string;
dynamicForm: {
title: string;
formType: string;
jsonData: Record<string, string>;
}[];
};
data: CreateFormRequest;
id: string;
}) => {
const response = await axios.post(`/api/form/${id}`, data);
Expand Down
9 changes: 3 additions & 6 deletions src/views/create-form/model/formCreateRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,10 @@ export const formCreateRouter = ({
router: AppRouterInstance;
}) => {
switch (navigation) {
case 'standard':
router.push(`/create-form/${id}?navigation=training`);
case 'STANDARD':
router.push(`/create-form/${id}?navigation=TRAINEE`);
break;
case 'training':
router.push(`/create-form/${id}?navigation=survey`);
break;
case 'survey':
case 'TRAINEE':
router.push('/');
break;
default:
Expand Down
12 changes: 3 additions & 9 deletions src/views/create-form/model/useCreateForm.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { AppRouterInstance } from 'next/dist/shared/lib/app-router-context.shared-runtime';
import { toast } from 'react-toastify';
import { CreateFormRequest } from '@/shared/types/create-form/type';
import { createForm } from '../api/createForm';
import { formCreateRouter } from './formCreateRouter';

Expand All @@ -13,15 +14,8 @@ export const useCreateForm = (

return useMutation({
mutationKey: ['createForm', id, navigation],
mutationFn: (formattedData: {
informationImage: string;
participantType: string;
dynamicForm: {
title: string;
formType: string;
jsonData: Record<string, string>;
}[];
}) => createForm({ data: formattedData, id }),
mutationFn: (formattedData: CreateFormRequest) =>
createForm({ data: formattedData, id }),
onSuccess: () => {
toast.success('폼이 생성되었습니다.');
formCreateRouter({ id, navigation, router });
Expand Down
41 changes: 27 additions & 14 deletions src/views/create-form/ui/createForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import { useRouter, useSearchParams } from 'next/navigation';
import { useEffect } from 'react';
import { useFieldArray, useForm } from 'react-hook-form';
import { toast } from 'react-toastify';
import { CreateFormButton } from '@/entities/create-form';
import { handleFormErrors } from '@/shared/model/formErrorUtils';
import { preventEvent } from '@/shared/model/preventEvent';
import { FormValues, Option } from '@/shared/types/create-form/type';
import { Button, PageHeader } from '@/shared/ui';
Expand All @@ -28,36 +30,44 @@ const CreateForm = ({ id }: { id: string }) => {
name: 'questions',
});

const showError = (message: string) => {
toast.error(message);
};

const {
mutate: createForm,
isPending,
isSuccess,
} = useCreateForm(id, navigation, router);

const onSubmit = (data: FormValues) => {
if (fields.length === 0) {
toast.error('최소 한 개의 폼을 추가해주세요');
return;
}
const formattedData = {
informationImage: '',
participantType: navigation?.toUpperCase() || 'STANDARD',
participantType: navigation || 'STANDARD',
dynamicForm: data.questions.map((question) => ({
title: question.title,
formType: question.formType,
jsonData: question.options.reduce(
(acc, option, index) => {
acc[(index + 1).toString()] = option.value;
return acc;
},
{} as Record<string, string>,
jsonData: JSON.stringify(
question.options.reduce(
(acc, option, index) => {
acc[(index + 1).toString()] = option.value;
return acc;
},
{} as Record<string, string>,
),
),
})),
};
console.log(formattedData);
createForm(formattedData);
};

const navigationTitles: Record<string, string> = {
standard: '참가자 폼',
training: '연수자 폼',
survey: '만족도 조사 폼',
STANDARD: '참가자 폼',
TRAINEE: '연수자 폼',
};

useEffect(() => {
Expand All @@ -68,11 +78,14 @@ const CreateForm = ({ id }: { id: string }) => {
<div className="flex h-screen flex-col gap-[30px] mobile:gap-0">
<Header />
<form
onSubmit={handleSubmit(onSubmit)}
className="mx-auto w-full max-w-[792px] flex-1 space-y-4 px-5"
onSubmit={handleSubmit(onSubmit, (errors) => {
console.log(errors);
handleFormErrors(errors, showError);
})}
className="mx-auto w-full max-w-[792px] flex-1 space-y-4 px-5 pb-5"
>
<PageHeader
title={navigationTitles[navigation || 'standard'] || '신청자 폼'}
title={navigationTitles[navigation || 'STANDARD'] || '신청자 폼'}
/>
<div className="w-full space-y-8">
{fields.map((field, index) => (
Expand Down
32 changes: 19 additions & 13 deletions src/widgets/create-form/ui/FormContainer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import {
Control,
useFieldArray,
Expand All @@ -17,7 +17,6 @@ import {
MultipleChoiceOption,
PictureOption,
RequiredToggle,
TextOption,
} from '@/entities/create-form';
import { preventEvent } from '@/shared/model/preventEvent';
import { FormValues, Option } from '@/shared/types/create-form/type';
Expand Down Expand Up @@ -51,15 +50,6 @@ const FormContainer = ({
});

const componentMap: Record<string, JSX.Element | null> = {
SENTENCE: (
<TextOption
fields={fields}
remove={remove}
register={register}
index={index}
isCheckBox={isCheckBox}
/>
),
CHECKBOX: (
<CheckBoxOption
fields={fields}
Expand Down Expand Up @@ -108,6 +98,19 @@ const FormContainer = ({
setIsCheckBox(!isCheckBox);
};

useEffect(() => {
if (selectedOption?.value === 'SENTENCE') {
setValue(`questions.${index}.options`, []);
}

if (
selectedOption?.value === 'SENTENCE' ||
selectedOption?.value === 'IMAGE'
) {
setIsCheckBox(false);
}
}, [selectedOption, index, setValue]);

return (
<div className="flex w-full flex-col gap-6 rounded-sm border-1 border-solid border-gray-200 px-[32px] py-[18px]">
<div className="flex w-full items-center justify-between">
Expand All @@ -123,10 +126,13 @@ const FormContainer = ({
</div>
{renderOptionComponent()}
<div className="border-b-1 border-solid border-gray-100 py-6">
<AddItemButton onClick={() => append({ value: '' })} />
{selectedOption?.value !== 'SENTENCE' ? (
<AddItemButton onClick={() => append({ value: '' })} />
) : null}
</div>
<div className="flex w-full items-center justify-end gap-6">
{selectedOption?.value !== 'IMAGE' ? (
{selectedOption?.value !== 'IMAGE' &&
selectedOption?.value !== 'SENTENCE' ? (
<CheckBox
toggleCheck={handleCheckBox}
isCheckBox={isCheckBox}
Expand Down
2 changes: 1 addition & 1 deletion src/widgets/expo-created/ui/ExpoCreatedContainer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Button } from '@/shared/ui';
const ExpoCreatedContainer = ({ id }: { id: string }) => {
const router = useRouter();
const handleButton = () => {
router.push(`/create-form/${id}?navigation=standard`);
router.push(`/create-form/${id}?navigation=STANDARD`);
};
return (
<div className="flex h-full w-full flex-col items-center justify-center gap-[40px]">
Expand Down

0 comments on commit 7783c37

Please sign in to comment.