-
Notifications
You must be signed in to change notification settings - Fork 39
[유동환] sprint6 #200
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
The head ref may contain hidden characters: "React-\uC720\uB3D9\uD658-sprint6"
[유동환] sprint6 #200
Changes from all commits
9cf3968
130b596
09d4d45
96cb1e7
3035ba3
e097fdd
90024ee
f780596
66803fa
aa41ac7
0737332
4449231
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 | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,175 @@ | ||||||||||
| import { | ||||||||||
| itemWrapper, | ||||||||||
| addItem, | ||||||||||
| contentHeader, | ||||||||||
| headerButton, | ||||||||||
| addItemBox, | ||||||||||
| addItemImageWrapper, | ||||||||||
| plusIconStyle, | ||||||||||
| imgRowWrapper, | ||||||||||
| previewBox, | ||||||||||
| previewImg, | ||||||||||
| deleteImage, | ||||||||||
| alertMessage, | ||||||||||
| itemHashTagWrapper, | ||||||||||
| ItemTag, | ||||||||||
| hashTagContainer, | ||||||||||
| } from './AddItemStyle' | ||||||||||
| import plusIcon from '../../assets/plusIcon.png' | ||||||||||
| import deleteIcon from '../../assets/deleteIcon.png' | ||||||||||
| import { useRef, useState } from 'react'; | ||||||||||
|
|
||||||||||
| /** @jsxImportSource @emotion/react */ | ||||||||||
|
|
||||||||||
| const AddItem = () => { | ||||||||||
| return <div>AddItem</div>; | ||||||||||
|
|
||||||||||
| const [imgPreviewUrl, setImgPreviewUrl] = useState(null); // 추가했을때 이미지프리뷰 | ||||||||||
| const [showWarning, setShowWarning] = useState(false); | ||||||||||
|
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 [itemName, setItemName] = useState(""); | ||||||||||
| const [itemDescription, setItemDiscription] = useState(""); | ||||||||||
| const [itemPrice, setItemPrice] = useState(""); | ||||||||||
| const [itemTag, setItemTag] = useState(""); | ||||||||||
| const [itemHashTag, setItemHashTag] = useState([]); | ||||||||||
|
|
||||||||||
| const handleFileChange = (e) => { | ||||||||||
| const file = e.target.files?.[0]; | ||||||||||
|
|
||||||||||
| if (imgPreviewUrl !== null) { | ||||||||||
| setShowWarning(true) | ||||||||||
| return | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if (file) { | ||||||||||
| const preview = URL.createObjectURL(file); | ||||||||||
| setImgPreviewUrl(preview) | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| const handleFileDelete = () => { | ||||||||||
| setImgPreviewUrl(null); | ||||||||||
| setShowWarning(false); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| const handleSubmitButton = () => { | ||||||||||
|
|
||||||||||
| } | ||||||||||
|
Comment on lines
+53
to
+55
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. ❗️ 수정요청
Suggested change
|
||||||||||
|
|
||||||||||
| const handleDeleteTag = (tagToDelete) => { | ||||||||||
| setItemHashTag(itemHashTag.filter(tag => tag !==tagToDelete)); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| const tagEndRef = useRef(null); // 태그 생성시 스크롤 이동을 위함 | ||||||||||
|
|
||||||||||
| return ( | ||||||||||
| <> | ||||||||||
| <form css={addItem}> | ||||||||||
| <div css={contentHeader}> | ||||||||||
| <h3>상품 등록하기</h3> | ||||||||||
| <button | ||||||||||
| type="submit" | ||||||||||
| css={headerButton} | ||||||||||
| onClick={handleSubmitButton} | ||||||||||
| disabled={ | ||||||||||
| itemName.trim() === "" || | ||||||||||
| itemDescription.trim() === "" || | ||||||||||
| itemPrice.trim() === "" || | ||||||||||
| itemHashTag.length === 0 || | ||||||||||
| !imgPreviewUrl | ||||||||||
| } | ||||||||||
| > | ||||||||||
| 등록 | ||||||||||
| </button> | ||||||||||
| </div> | ||||||||||
| <div css={itemWrapper}> | ||||||||||
| <div > | ||||||||||
| <p>상품 이미지</p> | ||||||||||
| <div css={imgRowWrapper}> | ||||||||||
| <label htmlFor='fileUpload' css={addItemImageWrapper}> | ||||||||||
| <div css={addItemBox}> | ||||||||||
| <img src={plusIcon} alt='추가' css={plusIconStyle} /> | ||||||||||
| <span>이미지 등록</span> | ||||||||||
| </div> | ||||||||||
| </label> | ||||||||||
| {imgPreviewUrl && ( | ||||||||||
| <div css={previewBox}> | ||||||||||
|
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. |
||||||||||
| <img src={imgPreviewUrl} alt='선택한 사진' css={previewImg} /> | ||||||||||
| <button onClick={handleFileDelete}> | ||||||||||
| <img src={deleteIcon} alt='삭제버튼' css={deleteImage} /> | ||||||||||
| </button> | ||||||||||
| </div> | ||||||||||
| )} | ||||||||||
| </div> | ||||||||||
| <input | ||||||||||
| id='fileUpload' | ||||||||||
| type='file' | ||||||||||
| accept='image/*' | ||||||||||
|
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. 💊 제안 (사용자가 업로드창에서 옵션을 열어 확장자를 바꾸면 아래처럼 보입니다) https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/accept |
||||||||||
| style={{display: 'none'}} | ||||||||||
| onChange={handleFileChange} | ||||||||||
| /> | ||||||||||
| </div> | ||||||||||
|
|
||||||||||
| {showWarning && ( | ||||||||||
| <p css={alertMessage}>이미지는 한 장만 선택할 수 있습니다.</p> | ||||||||||
| )} | ||||||||||
|
|
||||||||||
| <div> | ||||||||||
| <label htmlFor='name'>상품명</label> | ||||||||||
| <input id="name" placeholder="상품명을 입력해주세요" value={itemName} onChange={(e)=> setItemName(e.target.value)}></input> | ||||||||||
| </div> | ||||||||||
|
|
||||||||||
| <div> | ||||||||||
| <label>상품 소개</label> | ||||||||||
| <textarea id="description" placeholder="상품 소개를 입력해주세요" value={itemDescription} onChange={(e) => setItemDiscription(e.target.value)}></textarea> | ||||||||||
| </div> | ||||||||||
|
|
||||||||||
| <div> | ||||||||||
| <label>판매가격</label> | ||||||||||
| <input id="price" placeholder="판매가격을 입력해주세요" type='number' value={itemPrice} onChange={(e) => setItemPrice(e.target.value)}></input> | ||||||||||
|
Comment on lines
+126
to
+127
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. 💊 제안
Suggested change
|
||||||||||
| </div> | ||||||||||
|
|
||||||||||
| <div> | ||||||||||
| <label>태그</label> | ||||||||||
| <input | ||||||||||
| id="tag" | ||||||||||
| placeholder="태그를 입력해주세요" | ||||||||||
| value={itemTag} onChange={(e) => setItemTag(e.target.value)} | ||||||||||
| onKeyDown={(e) => { | ||||||||||
|
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. 💊 제안
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. ❗️ 수정요청 |
||||||||||
| if (e.key === "Enter"&& itemTag.trim() !== "") { | ||||||||||
| e.preventDefault(); | ||||||||||
|
|
||||||||||
| const newTag = itemTag.trim(); | ||||||||||
| if (!itemHashTag.includes(newTag)) { | ||||||||||
| setItemHashTag((prev) => [...prev, newTag]) | ||||||||||
| } | ||||||||||
|
Comment on lines
+141
to
+143
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. 💊 제안 |
||||||||||
| setItemTag("") | ||||||||||
| //태그 생성시 스크롤 이동 | ||||||||||
| setTimeout(() => { | ||||||||||
| tagEndRef.current?.scrollIntoView({behavior: "smooth"}) | ||||||||||
| },0) | ||||||||||
| } | ||||||||||
| }} | ||||||||||
| ></input> | ||||||||||
| </div> | ||||||||||
|
|
||||||||||
| {itemHashTag.length > 0 && ( | ||||||||||
| <div css={hashTagContainer}> | ||||||||||
| {itemHashTag.map((tag) => ( | ||||||||||
| <div key={tag} css={itemHashTagWrapper}> | ||||||||||
| <span css={ItemTag}> | ||||||||||
| #{tag} | ||||||||||
| </span> | ||||||||||
| <button type='button' onClick={() => handleDeleteTag(tag)}> | ||||||||||
| <img src={deleteIcon} alt='삭제버튼' css={deleteImage} /> | ||||||||||
| </button> | ||||||||||
| </div> | ||||||||||
| ))} | ||||||||||
| <div ref={tagEndRef} /> | ||||||||||
| </div> | ||||||||||
| )} | ||||||||||
| </div> | ||||||||||
| </form> | ||||||||||
| </> | ||||||||||
| ); | ||||||||||
| }; | ||||||||||
|
|
||||||||||
| export default AddItem; | ||||||||||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,201 @@ | ||||||||
| import { css } from '@emotion/react'; | ||||||||
|
|
||||||||
|
|
||||||||
| const itemWrapper = css` | ||||||||
| color: var(--gray-800); | ||||||||
| font-weight: 700; | ||||||||
| > div { | ||||||||
| margin-top: 32px; | ||||||||
| } | ||||||||
| > div > input, textarea { | ||||||||
| border-radius: 12px; | ||||||||
| width: 100%; | ||||||||
| height: 56px; | ||||||||
| background: var(--gray-100); | ||||||||
| margin-top: 16px; | ||||||||
| padding-left: 20px; | ||||||||
| border: none; | ||||||||
| cursor: pointer; | ||||||||
| > span { | ||||||||
| color: var(--gray-400); | ||||||||
| font-weight: 400; | ||||||||
| } | ||||||||
| } | ||||||||
| > div > textarea { | ||||||||
| height: 282px; | ||||||||
| padding-top: 15px; | ||||||||
| } | ||||||||
| // wrapper에 div 안 input, textarea, span 에 적용 | ||||||||
| > div > input::placeholder, textarea::placeholder, span { | ||||||||
| color: var(--gray-400); | ||||||||
| font-weight: 400; | ||||||||
| } | ||||||||
| ` | ||||||||
|
|
||||||||
| const addItem = css` | ||||||||
| max-width: 1200px; | ||||||||
| margin: 0 auto; | ||||||||
| padding: 0 16px; | ||||||||
| ` | ||||||||
| const contentHeader = css` | ||||||||
| width: auto; | ||||||||
| display: flex; | ||||||||
| justify-content: space-between; | ||||||||
| align-items: center; | ||||||||
| margin-top: 24px; | ||||||||
| > button { | ||||||||
| border-radius: 8px; | ||||||||
| border: none; | ||||||||
| width: 74px; | ||||||||
| height: 42px; | ||||||||
| background: var(--gray-400); | ||||||||
| color: white; | ||||||||
| } | ||||||||
| ` | ||||||||
|
|
||||||||
| const headerButton = css` | ||||||||
| cursor: pointer; | ||||||||
| &:not(:disabled) { | ||||||||
| background: var(--blue); | ||||||||
| } | ||||||||
| &:disabled { | ||||||||
| cursor: not-allowed; | ||||||||
| } | ||||||||
| ` | ||||||||
|
|
||||||||
| const addItemImageWrapper = css` | ||||||||
| ` | ||||||||
|
Comment on lines
+74
to
+76
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. ❗️ 수정요청
Suggested change
|
||||||||
|
|
||||||||
| const addItemBox = css` | ||||||||
| margin-top: 16px; | ||||||||
| display: flex; | ||||||||
| flex-direction: column; | ||||||||
| justify-content: center; | ||||||||
| align-items: center; | ||||||||
| gap: 12px; | ||||||||
| width: 282px; | ||||||||
| aspect-ratio: 1/1; | ||||||||
| background: var(--gray-100); | ||||||||
| border-radius: 12px; | ||||||||
| cursor: pointer; | ||||||||
| @media (max-width: 768px) { | ||||||||
| width: 168px; | ||||||||
| } | ||||||||
| ` | ||||||||
|
|
||||||||
| const plusIconStyle = css` | ||||||||
| width: 48px; | ||||||||
| aspect-ratio: 1/1; | ||||||||
| ` | ||||||||
|
|
||||||||
| const imgRowWrapper = css` | ||||||||
| display: flex; | ||||||||
| gap: 24px; | ||||||||
| @media (max-width: 768px) { | ||||||||
| gap: 10px; | ||||||||
| } | ||||||||
| ` | ||||||||
|
|
||||||||
| const previewBox = css` | ||||||||
| position: relative; | ||||||||
| margin-top: 16px; | ||||||||
| display: flex; | ||||||||
| width: 282px; | ||||||||
| aspect-ratio: 1/1; | ||||||||
| @media (max-width: 768px) { | ||||||||
| width: 168px; | ||||||||
| } | ||||||||
| > button { | ||||||||
| position: absolute; | ||||||||
| background: transparent; | ||||||||
| border: none; | ||||||||
| cursor: pointer; | ||||||||
| top: 8px; | ||||||||
| right: 8px; | ||||||||
| transition: all 0.2s ease; | ||||||||
| &:hover { | ||||||||
| transform: scale(1.1); | ||||||||
| } | ||||||||
| } | ||||||||
| ` | ||||||||
|
|
||||||||
| const previewImg = css` | ||||||||
| width: 100%; | ||||||||
| aspect-ratio: 1/1; | ||||||||
| object-fit: cover; | ||||||||
| border-radius: 12px; | ||||||||
| ` | ||||||||
|
|
||||||||
| const deleteImage = css` | ||||||||
| width: 22px; | ||||||||
| height: 24px; | ||||||||
| ` | ||||||||
|
|
||||||||
| const alertMessage = css` | ||||||||
| color: rgba(247, 71, 71, 1); | ||||||||
| font-weight: 400; | ||||||||
| font-size: 16px; | ||||||||
| ` | ||||||||
|
|
||||||||
| const itemHashTagWrapper = css` | ||||||||
| background: var(--gray-100); | ||||||||
| border-radius: 26px; | ||||||||
| display: inline-flex; | ||||||||
| padding: 5px 12px 5px 16px;; | ||||||||
| > span { | ||||||||
| color: var(--gray-800); | ||||||||
| display: flex; | ||||||||
| align-items: center; | ||||||||
| } | ||||||||
| > button { | ||||||||
| background: transparent; | ||||||||
| border: none; | ||||||||
| cursor: pointer; | ||||||||
| padding-top: 2px; | ||||||||
| } | ||||||||
| ` | ||||||||
|
|
||||||||
| const ItemTag = css` | ||||||||
|
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. ❗️수정요청 |
||||||||
| color: var(--gray-800); | ||||||||
| ` | ||||||||
|
|
||||||||
| const hashTagContainer = css` | ||||||||
| margin-top: 14px; | ||||||||
| display: flex; | ||||||||
| flex-wrap: wrap; | ||||||||
| gap: 12px; | ||||||||
| ` | ||||||||
|
|
||||||||
| export { | ||||||||
| itemWrapper, | ||||||||
| addItem, | ||||||||
| contentHeader, | ||||||||
| headerButton, | ||||||||
| addItemBox, | ||||||||
| addItemImageWrapper, | ||||||||
| plusIconStyle, | ||||||||
| imgRowWrapper, | ||||||||
| previewBox, | ||||||||
| previewImg, | ||||||||
| deleteImage, | ||||||||
| alertMessage, | ||||||||
| itemHashTagWrapper, | ||||||||
| ItemTag, | ||||||||
| hashTagContainer, | ||||||||
| }; | ||||||||


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.
💊 제안
하나의 파일이 너무 큰 것 같아요~
내부적으로 아이템 생성을 위한 로직들과 state가 custom hook으로 분리되고 UI 들도 컴포넌트로 분리되면,
가독성 측면에서 더 좋을 것 같아요.
컴포넌트로 분리하는 것은 생각의 단위를 나누는 것과 같이 때문에 너무 크게 가지고 가시면 로직을 파악하기도 어렵고 유지보수시에도불리합니다!