-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
π νΌ μμ± μ μΆ μ΄μ #86
Conversation
Walkthroughμ΄ ν 리νμ€νΈλ νΌ μμ± λ° μ μΆ νλ‘μΈμ€μ κ΄λ ¨λ μ¬λ¬ μ»΄ν¬λνΈμ API μλν¬μΈνΈμ λν κ΄λ²μν λ³κ²½ μ¬νμ ν¬ν¨νκ³ μμ΅λλ€. μ£Όμ λ³κ²½ μ¬νμ νΌ μμ± λ‘μ§μ μ ν¨μ± κ²μ¬ κ°ν, μλ΅ μ²λ¦¬ κ°μ , νμ μ μ μΆκ°, κ·Έλ¦¬κ³ μΌλΆ μ»΄ν¬λνΈμ μν κ΄λ¦¬ λ‘μ§ μμ μ ν¬ν¨ν©λλ€. Changes
Suggested labels
Suggested reviewers
Poem
β¨ Finishing Touches
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? πͺ§ TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
π Outside diff range comments (1)
src/views/create-form/api/createForm.ts (1)
Line range hint
10-12
: API νΈμΆμ λν μλ¬ μ²λ¦¬κ° νμν©λλ€.μλ² μλ΅ μ€ν¨λ λ€νΈμν¬ μ€λ₯μ λν μ²λ¦¬κ° μμ΅λλ€. μ μ ν μλ¬ μ²λ¦¬λ₯Ό μΆκ°νλ κ²μ΄ μ’κ² μ΅λλ€.
export const createForm = async ({ data, id, }: { data: CreateFormRequest; id: string; }) => { - const response = await axios.post(`/api/form/${id}`, data); - return response; + try { + const response = await axios.post(`/api/form/${id}`, data); + return response; + } catch (error) { + if (axios.isAxiosError(error)) { + throw new Error(`νΌ μμ± μ€ν¨: ${error.message}`); + } + throw error; + } };
π§Ή Nitpick comments (7)
src/entities/create-form/ui/FormTitle/index.tsx (1)
14-16
: νΌ μ ν¨μ± κ²μ¬κ° μ μ ν μΆκ°λμμ΅λλ€.νμ μ λ ₯ κ²μ¦μ΄ μ ꡬνλμμΌλ©°, μΈλ±μ€λ₯Ό νμ©ν λμ μλ¬ λ©μμ§ μμ±μ΄ ν¨κ³Όμ μ λλ€.
μλ¬ λ©μμ§ κ΄λ¦¬ κ°μ μ μ μλ립λλ€.
νμ¬ μλ¬ λ©μμ§κ° μ»΄ν¬λνΈμ μ§μ νλμ½λ©λμ΄ μμ΅λλ€. λ€κ΅μ΄ μ§μμ΄λ λ©μμ§ μΌκ΄μ±μ μν΄ μμ νμΌλ‘ λΆλ¦¬νλ κ²μ κ³ λ €ν΄λ³΄μΈμ.
λ€μκ³Ό κ°μ΄ κ°μ ν μ μμ΅λλ€:
+// src/shared/constants/errorMessages.ts +export const ERROR_MESSAGES = { + FORM_TITLE_REQUIRED: (index: number) => `${index + 1}λ² νΌμ μ λͺ©μ μ λ ₯ν΄μ£ΌμΈμ`, +}; // FormTitle component - required: `${index + 1}λ² νΌμ μ λͺ©μ μ λ ₯ν΄μ£ΌμΈμ`, + required: ERROR_MESSAGES.FORM_TITLE_REQUIRED(index),src/views/create-form/model/formCreateRouter.ts (1)
13-14
: λ€λΉκ²μ΄μ μμ μ μκ° νμν©λλ€.λ€λΉκ²μ΄μ κ°λ€μ μμλ‘ μ μνμ¬ νμ μμ μ±μ λμ΄κ³ μ¬μ¬μ©μ±μ κ°μ νλ κ²μ΄ μ’κ² μ΅λλ€.
+export const NAVIGATION_TYPES = { + STANDARD: 'STANDARD', + TRAINEE: 'TRAINEE', +} as const; + +type NavigationType = typeof NAVIGATION_TYPES[keyof typeof NAVIGATION_TYPES]; + export const formCreateRouter = ({ id, navigation, router, }: { id: string; - navigation: string | null; + navigation: NavigationType | null; router: AppRouterInstance; }) => { switch (navigation) { - case 'STANDARD': - router.push(`/create-form/${id}?navigation=TRAINEE`); + case NAVIGATION_TYPES.STANDARD: + router.push(`/create-form/${id}?navigation=${NAVIGATION_TYPES.TRAINEE}`); break; - case 'TRAINEE': + case NAVIGATION_TYPES.TRAINEE: router.push('/'); break; default: + console.warn(`μ μ μλ λ€λΉκ²μ΄μ νμ : ${navigation}`); break; } };Also applies to: 16-17
src/shared/types/create-form/type.ts (1)
25-33
: μΈν°νμ΄μ€μ λν λ¬Έμνκ° νμν©λλ€.κ° νλμ λͺ©μ κ³Ό μ μ½μ¬νμ μ€λͺ νλ JSDoc λ¬Έμλ₯Ό μΆκ°νλ©΄ μ’κ² μ΅λλ€.
+/** + * νΌ μμ± μμ²μ λν λ°μ΄ν° ꡬ쑰 + */ export interface CreateFormRequest { + /** μ 보 μ΄λ―Έμ§μ URL λλ base64 λ¬Έμμ΄ */ informationImage: string; + /** μ°Έκ°μ μ ν μλ³μ */ participantType: string; + /** λμ νΌ νλ λ°°μ΄ */ dynamicForm: { + /** νΌ νλμ μ λͺ© */ title: string; + /** νΌ νλμ μ ν */ formType: string; + /** JSON λ°μ΄ν°λ₯Ό λ¬Έμμ΄λ‘ λ³νν κ° */ jsonData: string; }[]; }src/app/api/form/[expo_id]/route.ts (1)
23-26
: μλ΅ μ²λ¦¬κ° κ°μ λμμΌλ μΆκ° κ°μ μ΄ κ°λ₯ν©λλ€.μλ΅ μ²λ¦¬κ°
NextResponse
λ₯Ό μ¬μ©νμ¬ κ°μ λμμ΅λλ€. λ€λ§ λ€μκ³Ό κ°μ μΆκ° κ°μ μ μ μλ립λλ€:
- μ±κ³΅ μλ΅μ μν μ½λλ₯Ό λͺ μμ μΌλ‘ 201λ‘ μ€μ
- CORS ν€λ μΆκ° κ³ λ €
λ€μκ³Ό κ°μ΄ μμ νλ κ²μ μ μλ립λλ€:
- return new NextResponse(JSON.stringify(response.data), { - status: response.status, - headers: { 'Content-Type': 'application/json' }, - }); + return new NextResponse(JSON.stringify(response.data), { + status: 201, + headers: { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*', + }, + });src/views/create-form/ui/createForm/index.tsx (2)
54-61
: λ°μ΄ν° λ³ν λ‘μ§ κ°μ μ΄ νμν©λλ€.νμ¬ κ΅¬νμ μλνμ§λ§, κ°λ μ±κ³Ό μ μ§λ³΄μμ±μ μν΄ λ€μκ³Ό κ°μ κ°μ μ μ μλ립λλ€:
- jsonData: JSON.stringify( - question.options.reduce( - (acc, option, index) => { - acc[(index + 1).toString()] = option.value; - return acc; - }, - {} as Record<string, string>, - ), - ), + jsonData: JSON.stringify( + Object.fromEntries( + question.options.map((option, index) => [ + (index + 1).toString(), + option.value, + ]), + ), + ),
81-84
: μλ¬ λ‘κΉ κ°μ μ΄ νμν©λλ€.μ½μ λ‘κ·Έλ₯Ό νλ‘λμ νκ²½μμ μ κ±°νκ±°λ proper λ‘κΉ μμ€ν μΌλ‘ λ체νλ κ²μ΄ μ’μ΅λλ€.
- onSubmit={handleSubmit(onSubmit, (errors) => { - console.log(errors); - handleFormErrors(errors, showError); - })} + onSubmit={handleSubmit(onSubmit, (errors) => { + handleFormErrors(errors, showError); + })}src/widgets/create-form/ui/FormContainer/index.tsx (1)
101-112
: useEffect ꡬνμ΄ μ μ ν©λλ€!μ΅μ μ΄κΈ°νμ 체ν¬λ°μ€ μν κ΄λ¦¬κ° μ ꡬνλμ΄ μμ΅λλ€. λ€λ§, κ°λ μ± ν₯μμ μν΄ μ‘°κ±΄λ¬Έμ μμλ‘ μΆμΆνλ κ²μ κ³ λ €ν΄λ³΄μΈμ.
+ const isSentenceType = selectedOption?.value === 'SENTENCE'; + const isImageType = selectedOption?.value === 'IMAGE'; + useEffect(() => { - if (selectedOption?.value === 'SENTENCE') { + if (isSentenceType) { setValue(`questions.${index}.options`, []); } - if ( - selectedOption?.value === 'SENTENCE' || - selectedOption?.value === 'IMAGE' - ) { + if (isSentenceType || isImageType) { setIsCheckBox(false); } }, [selectedOption, index, setValue]);
π Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
π Files selected for processing (13)
src/app/api/form/[expo_id]/route.ts
(1 hunks)src/entities/create-form/index.tsx
(0 hunks)src/entities/create-form/ui/FormTitle/index.tsx
(1 hunks)src/entities/create-form/ui/OptionItem/index.tsx
(1 hunks)src/entities/create-form/ui/TextOption/index.tsx
(0 hunks)src/shared/types/create-form/type.ts
(1 hunks)src/shared/ui/ToggleButton/index.tsx
(1 hunks)src/views/create-form/api/createForm.ts
(1 hunks)src/views/create-form/model/formCreateRouter.ts
(1 hunks)src/views/create-form/model/useCreateForm.ts
(2 hunks)src/views/create-form/ui/createForm/index.tsx
(3 hunks)src/widgets/create-form/ui/FormContainer/index.tsx
(3 hunks)src/widgets/expo-created/ui/ExpoCreatedContainer/index.tsx
(1 hunks)
π€ Files with no reviewable changes (2)
- src/entities/create-form/index.tsx
- src/entities/create-form/ui/TextOption/index.tsx
β Files skipped from review due to trivial changes (1)
- src/widgets/expo-created/ui/ExpoCreatedContainer/index.tsx
π Additional comments (5)
src/views/create-form/api/createForm.ts (1)
2-2
: νμ μ μ κ°μ μ΄ μ μ΄λ£¨μ΄μ‘μ΅λλ€.λ³λμ νμ νμΌλ‘ λΆλ¦¬νμ¬ μ¬μ¬μ©μ±κ³Ό μ μ§λ³΄μμ±μ΄ ν₯μλμμ΅λλ€.
Also applies to: 8-8
src/views/create-form/model/useCreateForm.ts (1)
4-4
: νμ μμ μ±μ΄ κ°μ λμμ΅λλ€! π
CreateFormRequest
νμ μ λμ νμ¬ νΌ λ°μ΄ν°μ νμ μμ μ±μ΄ ν₯μλμμ΅λλ€. μ΄λ λ°νμ μ€λ₯λ₯Ό λ°©μ§νκ³ μ½λμ μ μ§λ³΄μμ±μ λμ΄λλ° λμμ΄ λ©λλ€.Also applies to: 17-18
src/entities/create-form/ui/OptionItem/index.tsx (1)
28-28
: νμ μ λ ₯ μ ν¨μ± κ²μ¬κ° μΆκ°λμμ΅λλ€! πμ΅μ μ λ ₯ νλμ νμ μ λ ₯ μ ν¨μ± κ²μ¬λ₯Ό μΆκ°ν κ²μ μ’μ κ°μ μ λλ€. μ¬μ©μμκ² λͺ νν μλ¬ λ©μμ§λ₯Ό μ 곡νμ¬ UXκ° ν₯μλμμ΅λλ€.
src/views/create-form/ui/createForm/index.tsx (2)
33-35
: μλ¬ μ²λ¦¬ ν¨μκ° μΆκ°λμμ΅λλ€! π
showError
ν¨μλ₯Ό ν΅ν΄ μΌκ΄λ μλ¬ μ²λ¦¬ λ°©μμ μ 곡νλ κ²μ μ’μ μ κ·Όμ λλ€.
44-47
: νΌ μ ν¨μ± κ²μ¬κ° μΆκ°λμμ΅λλ€! πμ΅μ ν κ°μ νΌμ΄ νμνλ€λ μ ν¨μ± κ²μ¬λ₯Ό μΆκ°ν κ²μ μ’μ κ°μ μ λλ€.
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' | ||
}`} | ||
/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
μ κ·Όμ± μμ±κ³Ό 컀μ€ν°λ§μ΄μ§ κΈ°λ₯μ΄ νμν©λλ€.
- μ κ·Όμ±μ μν ARIA μμ±μ΄ λλ½λμμ΅λλ€.
- μ»΄ν¬λνΈμ μ¬μ¬μ©μ±μ μν΄ μμκ³Ό ν¬κΈ°λ₯Ό propsλ‘ λ°λλ‘ κ°μ μ΄ νμν©λλ€.
+interface ToggleButtonProps {
+ onChange?: (isToggled: boolean) => void;
+ defaultValue?: boolean;
+ ariaLabel?: string;
+}
+
-function ToggleButton() {
+function ToggleButton({
+ onChange,
+ defaultValue = false,
+ ariaLabel = 'ν κΈ λ²νΌ',
+}: ToggleButtonProps) {
- const [isToggled, setIsToggled] = useState(false);
+ const [isToggled, setIsToggled] = useState(defaultValue);
const toggle = (e: React.MouseEvent) => {
preventEvent(e);
- setIsToggled(!isToggled);
+ const newValue = !isToggled;
+ setIsToggled(newValue);
+ onChange?.(newValue);
};
return (
<button
+ role="switch"
+ aria-checked={isToggled}
+ aria-label={ariaLabel}
onClick={toggle}
className={`relative inline-flex h-6 w-12 items-center rounded-full transition-colors ${
isToggled ? 'bg-main-100' : 'bg-gray-100'
}`}
>
Committable suggestion skipped: line range outside the PR's diff.
{selectedOption?.value !== 'SENTENCE' ? ( | ||
<AddItemButton onClick={() => append({ value: '' })} /> | ||
) : null} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
μ‘°κ±΄λΆ λ λλ§ λ‘μ§μ κ°μ νμΈμ.
λμΌν μ‘°κ±΄μ΄ μ¬λ¬ κ³³μμ λ°λ³΅λκ³ μμ΅λλ€. μμλ‘ μΆμΆνμ¬ μ¬μ¬μ©νλ©΄ μ½λμ μ μ§λ³΄μμ±μ΄ ν₯μλ κ²μ λλ€.
+ const isSentenceType = selectedOption?.value === 'SENTENCE';
+ const isImageType = selectedOption?.value === 'IMAGE';
+ const showOptions = !isSentenceType;
+ const showCheckBox = !isSentenceType && !isImageType;
// ...
- {selectedOption?.value !== 'SENTENCE' ? (
+ {showOptions && (
<AddItemButton onClick={() => append({ value: '' })} />
- ) : null}
)}
// ...
- {selectedOption?.value !== 'IMAGE' &&
- selectedOption?.value !== 'SENTENCE' ? (
+ {showCheckBox && (
<CheckBox
toggleCheck={handleCheckBox}
isCheckBox={isCheckBox}
text="κΈ°ν"
/>
- ) : null}
)}
Also applies to: 134-135
π‘ λ°°κ²½ λ° κ°μ
μλ²μμ λ°μ΄ν°λ₯Ό JSONμ΄ μλλΌ λ¬Έμμ΄λ‘ λ°λλ‘ μ€κ³νμ¬ κΈ°μ‘΄μ 보λ΄λ νμμ΄ μλ μλ‘μ΄ λ°©λ²μ μ μ©ν΄μΌ νμλ€.
π μμ λ΄μ©
π λ³κ²½μ¬ν
{"1": "μ΄λ±νκ΅", "2": "μ€νκ΅", "3": "κ³ λ±νκ΅", "4": "λνκ΅"} => {"1":"μ΄λ±νκ΅","2":"μ€νκ΅","3":"κ³ λ±νκ΅","4":"λνκ΅"}"
Summary by CodeRabbit
μλ‘μ΄ κΈ°λ₯
λ²κ·Έ μμ
리ν©ν λ§
μ κ±°λ κΈ°λ₯
TextOption
μ»΄ν¬λνΈ μ κ±°