-
Notifications
You must be signed in to change notification settings - Fork 0
문의하기 ui api 연결 (#issue 256) #259
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
Changes from 7 commits
8905a74
0f7d73e
2bbf3c1
e567a5e
f9d538a
b7a30d7
ed5c7fc
44d32c2
c185020
c3b4cdd
6526cdf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import { httpClient } from './http.api'; | ||
|
|
||
| export const postInquiry = async (formData: FormData) => { | ||
| try { | ||
| const response = await httpClient.post('/inquiry', formData, { | ||
| headers: { | ||
| 'Content-Type': 'multipart/form-data', | ||
| }, | ||
| }); | ||
| console.log(response); | ||
| } catch (e) { | ||
| console.log('문의하기 에러', e); | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,191 @@ | ||
| import { ChevronDownIcon } from '@heroicons/react/24/outline'; | ||
| import styled, { css } from 'styled-components'; | ||
|
|
||
| export const Container = styled.main` | ||
| width: 100%; | ||
| display: flex; | ||
| justify-content: center; | ||
| flex-direction: column; | ||
| `; | ||
|
|
||
| export const Header = styled.header` | ||
| margin: 1rem 0; | ||
| display: flex; | ||
| justify-content: center; | ||
| `; | ||
|
|
||
| export const HeaderTitle = styled.h1``; | ||
|
|
||
| export const InquiryForm = styled.form` | ||
| width: 100%; | ||
| display: flex; | ||
| justify-content: center; | ||
| `; | ||
|
|
||
| export const InquiryWrapper = styled.div` | ||
| width: 49rem; | ||
| `; | ||
|
|
||
| export const Nav = styled.nav` | ||
| width: 100%; | ||
| display: flex; | ||
| gap: 0.5rem; | ||
| `; | ||
|
|
||
| export const CategoryWrapper = styled.div` | ||
| position: relative; | ||
| `; | ||
|
|
||
| export const CategorySelect = styled.button<{ $isOpen: boolean }>` | ||
| padding: 0.3rem 0.5rem; | ||
| width: 9rem; | ||
| display: flex; | ||
| justify-content: space-between; | ||
| align-items: center; | ||
| font-size: 1.3rem; | ||
| border: 1px solid ${({ theme }) => theme.color.border}; | ||
| border-radius: ${({ theme }) => theme.borderRadius.primary}; | ||
|
|
||
| svg { | ||
| width: 1.3rem; | ||
| height: 1.3rem; | ||
| transition: transform 300ms ease-in-out; | ||
| transform: rotate(0deg); | ||
| ${({ $isOpen }) => | ||
| $isOpen && | ||
| css` | ||
| transform: rotate(180deg); | ||
| `} | ||
| } | ||
| `; | ||
|
|
||
| export const CategoryValueInput = styled.input` | ||
| position: absolute; | ||
| width: 0; | ||
| height: 0; | ||
| overflow: hidden; | ||
| `; | ||
|
|
||
| export const CategoryButtonWrapper = styled.div` | ||
| width: 9rem; | ||
| position: absolute; | ||
| display: flex; | ||
| flex-direction: column; | ||
| overflow: hidden; | ||
| border: 1px solid ${({ theme }) => theme.color.border}; | ||
| border-radius: ${({ theme }) => theme.borderRadius.primary}; | ||
| background: ${({ theme }) => theme.color.white}; | ||
| `; | ||
|
|
||
| export const CategoryButton = styled.button` | ||
| font-size: 1.3rem; | ||
| padding: 0.5rem; | ||
| display: flex; | ||
| justify-content: start; | ||
| align-items: center; | ||
|
|
||
| &:hover { | ||
| background: ${({ theme }) => theme.color.navy}; | ||
| color: ${({ theme }) => theme.color.white}; | ||
| } | ||
| `; | ||
|
|
||
| export const InputInquiryTitle = styled.input` | ||
| padding: 0.2rem 0.8rem; | ||
| width: calc(100% - 8rem); | ||
| font-size: 1.3rem; | ||
| border: 1px solid ${({ theme }) => theme.color.border}; | ||
| border-radius: ${({ theme }) => theme.borderRadius.primary}; | ||
| `; | ||
|
|
||
| export const ContentWrapper = styled.section` | ||
| width: 100%; | ||
| `; | ||
|
|
||
| export const Content = styled.textarea` | ||
| resize: none; | ||
| margin: 0.5rem 0; | ||
| padding: 1rem; | ||
| height: 55vh; | ||
| width: 100%; | ||
| border: 1px solid ${({ theme }) => theme.color.border}; | ||
| border-radius: ${({ theme }) => theme.borderRadius.primary}; | ||
| font-size: 1rem; | ||
| `; | ||
|
|
||
| export const InquiryFileWrapper = styled.div` | ||
| display: flex; | ||
| height: 40px; | ||
| `; | ||
|
|
||
| export const InquiryFileLabel = styled.label` | ||
| display: flex; | ||
| justify-content: center; | ||
| align-items: center; | ||
| cursor: pointer; | ||
| font-size: 1rem; | ||
| width: 6rem; | ||
| background: ${({ theme }) => theme.color.navy}; | ||
| color: ${({ theme }) => theme.color.white}; | ||
| border: 1px solid ${({ theme }) => theme.color.navy}; | ||
| border-radius: ${({ theme }) => theme.borderRadius.primary} 0 0 | ||
| ${({ theme }) => theme.borderRadius.primary}; | ||
|
|
||
| &:hover { | ||
| background: ${({ theme }) => theme.color.lightgrey}; | ||
| color: ${({ theme }) => theme.color.navy}; | ||
| border: 1px solid ${({ theme }) => theme.color.navy}; | ||
| transition: all 0.3s ease-in-out; | ||
| } | ||
| `; | ||
|
|
||
| export const InquiryShowFile = styled.span` | ||
| display: flex; | ||
| justify-content: start; | ||
| align-items: center; | ||
| padding: 0.5rem; | ||
| border: 1px solid ${({ theme }) => theme.color.border}; | ||
| width: 40%; | ||
| color: ${({ theme }) => theme.color.navy}; | ||
| border-radius: 0 ${({ theme }) => theme.borderRadius.primary} | ||
| ${({ theme }) => theme.borderRadius.primary} 0; | ||
| `; | ||
|
|
||
| export const InquiryFile = styled.input` | ||
| position: absolute; | ||
| width: 0; | ||
| height: 0; | ||
| overflow: hidden; | ||
| `; | ||
|
|
||
| export const FileImg = styled.img` | ||
| margin-left: 0.5rem; | ||
| width: 60px; | ||
| height: 40px; | ||
| `; | ||
|
|
||
| export const SendButtonWrapper = styled.div` | ||
| width: 100%; | ||
| display: flex; | ||
| justify-content: end; | ||
| `; | ||
|
|
||
| export const SendButton = styled.button` | ||
| display: flex; | ||
| justify-content: center; | ||
| align-items: center; | ||
| font-size: 1rem; | ||
| width: 6rem; | ||
| background: ${({ theme }) => theme.color.navy}; | ||
| border-radius: ${({ theme }) => theme.borderRadius.large}; | ||
| color: ${({ theme }) => theme.color.white}; | ||
| border: 1px solid ${({ theme }) => theme.color.navy}; | ||
| padding: 0.5em; | ||
|
|
||
| &:hover { | ||
| background: ${({ theme }) => theme.color.lightgrey}; | ||
| color: ${({ theme }) => theme.color.navy}; | ||
| border: 1px solid ${({ theme }) => theme.color.navy}; | ||
| transition: all 0.3s ease-in-out; | ||
| } | ||
| `; |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,159 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Fragment } from 'react/jsx-runtime'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| EMPTY_IMAGE, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| INQUIRY_CATEGORY, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| INQUIRY_MESSAGE, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from '../../../../constants/customerService'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import * as S from './Inquiry.styled'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { ChevronDownIcon } from '@heroicons/react/24/outline'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import React, { useState } from 'react'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import type { InquiryFormData } from '../../../../models/inquiry'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { usePostInquiry } from '../../../../hooks/usePostInquiry'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| interface FormStateType { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| category: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fileValue: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fileImage: string | null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export default function Inquiry() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { mutate: postInquiry } = usePostInquiry(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [isOpen, setIsOpen] = useState<boolean>(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [form, setForm] = useState<FormStateType>({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| category: INQUIRY_MESSAGE.categoryDefault, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title: '', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content: '', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fileValue: INQUIRY_MESSAGE.fileDefault, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fileImage: null, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handleSubmitInquiry = (e: React.FormEvent<HTMLFormElement>) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e.preventDefault(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const formData = new FormData(e.currentTarget as HTMLFormElement); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const formDataObj: InquiryFormData = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| category: formData.get('category') as string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title: formData.get('title') as string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content: formData.get('content') as string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const data = new Blob([JSON.stringify(formDataObj)], { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: 'application/json', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| formData.append('inquiryDto', data); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 모달처리하기 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let isValid = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Array.from(formData.entries()).forEach(([key, value]) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (key === 'category' && value === INQUIRY_MESSAGE.categoryDefault) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return (isValid = false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (key === 'title' && value === '') return (isValid = false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (key === 'content' && value === '') return (isValid = false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isValid) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| postInquiry(formData); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setForm({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| category: INQUIRY_MESSAGE.categoryDefault, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title: '', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content: '', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fileValue: INQUIRY_MESSAGE.fileDefault, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fileImage: null, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분도 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handleClickCategoryValue = (category: string) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setForm((prev) => ({ ...prev, category })); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsOpen((prev) => !prev); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handleChangeFile = (e: React.ChangeEvent<HTMLInputElement>) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const fileValue = e.target.value; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const image = e.target.files?.[0]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const fileImage = image ? URL.createObjectURL(image) : null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setForm((prev) => ({ ...prev, fileValue, fileImage })); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 메모리 누수 방지를 위해 객체 URL을 관리하세요.
import React, { useState, useEffect } from 'react';
// ...
const handleChangeFile = (e: React.ChangeEvent<HTMLInputElement>) => {
const fileValue = e.target.value;
const image = e.target.files?.[0];
const fileImage = image ? URL.createObjectURL(image) : null;
setForm((prev) => ({ ...prev, fileValue, fileImage }));
};
+ // 컴포넌트 언마운트 시 객체 URL 해제
+ useEffect(() => {
+ return () => {
+ if (form.fileImage) {
+ URL.revokeObjectURL(form.fileImage);
+ }
+ };
+ }, [form.fileImage]);📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.Container> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.Header> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.HeaderTitle>DevPals 문의하기</S.HeaderTitle> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </S.Header> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.InquiryForm | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSubmit={handleSubmitInquiry} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| method='post' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| encType='multipart/form-data' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.InquiryWrapper> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.Nav> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.CategoryWrapper> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.CategorySelect | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClick={() => setIsOpen((prev) => !prev)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $isOpen={isOpen} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {form.category} <ChevronDownIcon /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.CategoryValueInput | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type='hidden' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name='category' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value={form.category} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </S.CategorySelect> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {isOpen && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.CategoryButtonWrapper> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {INQUIRY_CATEGORY.map((category) => ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Fragment key={category.title}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.CategoryButton | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClick={() => handleClickCategoryValue(category.title)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {category.title} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </S.CategoryButton> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Fragment> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </S.CategoryButtonWrapper> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </S.CategoryWrapper> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.InputInquiryTitle | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name='title' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type='text' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| placeholder='제목을 입력하세요.' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value={form.title} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onChange={(e) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setForm((prev) => ({ ...prev, title: e.target.value })) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </S.Nav> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.ContentWrapper> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.Content | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| as='textarea' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name='content' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value={form.content} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onChange={(e) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setForm((prev) => ({ ...prev, content: e.target.value })) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ></S.Content> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.InquiryFileWrapper> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.InquiryFileLabel htmlFor='upload'>파일찾기</S.InquiryFileLabel> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.InquiryShowFile>{form.fileValue}</S.InquiryShowFile> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.InquiryFile | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name='images' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type='file' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| accept='.jpg, .jpeg, .png' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id='upload' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onChange={(e) => handleChangeFile(e)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 파일 업로드 크기 제한을 추가하세요. 현재 이미지 파일 형식은 제한되어 있지만, 파일 크기에 대한 제한이 없습니다. 대용량 이미지 파일은 성능 문제를 일으킬 수 있으므로 크기 제한을 추가하는 것이 좋습니다. const handleChangeFile = (e: React.ChangeEvent<HTMLInputElement>) => {
const fileValue = e.target.value;
const image = e.target.files?.[0];
+
+ // 파일 크기 제한 (예: 5MB)
+ const MAX_FILE_SIZE = 5 * 1024 * 1024;
+ if (image && image.size > MAX_FILE_SIZE) {
+ alert('파일 크기는 5MB 이하여야 합니다.');
+ e.target.value = '';
+ return;
+ }
+
const fileImage = image ? URL.createObjectURL(image) : null;
setForm((prev) => ({ ...prev, fileValue, fileImage }));
};📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {form.fileImage && <S.FileImg src={form.fileImage || ''} />} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </S.InquiryFileWrapper> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </S.ContentWrapper> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.SendButtonWrapper> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <S.SendButton type='submit'>제출</S.SendButton> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </S.SendButtonWrapper> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </S.InquiryWrapper> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </S.InquiryForm> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </S.Container> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. customerService폴더가 common에 들어가 있는데, 잘 못 넣으신 것 같아요
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 문의하기가 헤더 유저 토스트부분이랑 마이페이지 내 문의글, 그리고 FAQ 공지사항 각각 들어가서 common으로 했습니다. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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
에러 처리 및 반환 값 개선이 필요합니다
현재 API 함수는 console.log를 사용하여 응답과 오류를 기록하고 있으며, 반환 값이 없습니다. 이는 호출하는 컴포넌트에서 성공/실패 여부를 확인하기 어렵게 만듭니다.
다음과 같이 개선하는 것을 추천합니다:
이렇게 수정하면:
📝 Committable suggestion