-
Notifications
You must be signed in to change notification settings - Fork 39
[송시은] Sprint7 #219
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
Merged
GANGYIKIM
merged 25 commits into
codeit-bootcamp-frontend:React-송시은
from
sgoldenbird:React-송시은-sprint7
May 16, 2025
The head ref may contain hidden characters: "React-\uC1A1\uC2DC\uC740-sprint7"
Merged
[송시은] Sprint7 #219
Changes from all commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
946c505
feat: add product detail route
sgoldenbird b339454
feat: create DropdownBtn component
sgoldenbird 6b10a4a
refactor: change SortDrop using DropdownBtn
sgoldenbird 59b36d0
feat: separate wrapper width into icon mode and text mode
sgoldenbird 2748f3d
feat: create tagHelpers.module.scss
sgoldenbird 91cd7d9
feat: create ProductInfo component
sgoldenbird bd6ae14
style: make ProductInfo component responsive
sgoldenbird f1b506b
feat: create CommentInput component
sgoldenbird 2e20c73
feat: create CommentList component
sgoldenbird f8d925a
feat: create ProductDetail page
sgoldenbird 854d791
chore: add _redirect
sgoldenbird d26cd45
fix: add Netlify SPA redirect config via netlify.toml
sgoldenbird 9c8144c
fix: correct Vite base path for Netlify deployment
sgoldenbird 2b44253
feat: create no comment list UI
sgoldenbird bf1c573
feat: create CommentItem component and edit, delete comment logic
sgoldenbird f2370c6
feat: create UserContext
sgoldenbird cb173de
refactor: remove Toast on safe fetch function
sgoldenbird 15e1ef4
feat: split error message handlers by HTTP method and resource type
sgoldenbird c200e81
refactor: apply status-based error messages to all product-related fe…
sgoldenbird 93b1449
feat: navigate to product detail page after successful add item
sgoldenbird c0acf35
refactor: apply constants to error messages
sgoldenbird e52afed
refactor: modularize fetch logic
sgoldenbird 3789f87
fix: reset file input when removing image to allow re-upload of same …
sgoldenbird aa4e70a
feat: Added delete and update logic to product info
sgoldenbird 4585d11
fix: receive id prop correctly
sgoldenbird File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| [[redirects]] | ||
| from = "/*" | ||
| to = "/index.html" | ||
| status = 200 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| /* /index.html 200 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import { baseUrl, ENDPOINTS } from '@/constants/urls'; | ||
| import { | ||
| requestPost, | ||
| requestGet, | ||
| requestDelete, | ||
| requestPatch, | ||
| } from './request'; | ||
|
|
||
| // 댓글 등록 | ||
| export const postComment = (productId, content) => { | ||
| const url = `${baseUrl}${ENDPOINTS.PRODUCTS}/${productId}${ENDPOINTS.COMMENTS}`; | ||
| return requestPost(url, { content }); | ||
| }; | ||
|
|
||
| // 댓글 조회 | ||
| export const getComments = (productId, cursor) => { | ||
| const query = cursor ? `?limit=10&cursor=${cursor}` : '?limit=10'; | ||
| const url = `${baseUrl}${ENDPOINTS.PRODUCTS}/${productId}${ENDPOINTS.COMMENTS}${query}`; | ||
| return requestGet(url); | ||
| }; | ||
|
|
||
| // 댓글 수정 | ||
| export const patchComment = (commentId, content) => { | ||
| const url = `${baseUrl}${ENDPOINTS.COMMENTS}/${commentId}`; | ||
| return requestPatch(url, { content }); | ||
| }; | ||
|
|
||
| // 댓글 삭제 | ||
| export const deleteComment = (commentId) => { | ||
| const url = `${baseUrl}${ENDPOINTS.COMMENTS}/${commentId}`; | ||
| return requestDelete(url); | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| import { baseUrl, ENDPOINTS } from '@/constants/urls'; | ||
| import { | ||
| requestPost, | ||
| requestGet, | ||
| requestPatch, | ||
| requestDelete, | ||
| } from './request'; | ||
|
|
||
| // 상품 등록 | ||
| export const postProduct = (formData) => { | ||
| const url = `${baseUrl}${ENDPOINTS.PRODUCTS}`; | ||
| return requestPost(url, formData); | ||
| }; | ||
|
|
||
| // 이미지 업로드 (FormData) | ||
| export const uploadImage = (formData) => { | ||
| const url = `${baseUrl}${ENDPOINTS.UPLOAD_IMAGE}`; | ||
| return requestPost(url, formData); | ||
| }; | ||
|
|
||
| // 상품 전체 조회 | ||
| export const fetchAllProducts = ({ page, pageSize, orderBy, keyword }) => { | ||
| const query = `?page=${page}&pageSize=${pageSize}&orderBy=${orderBy}&keyword=${encodeURIComponent(keyword || '')}`; | ||
| const url = `${baseUrl}${ENDPOINTS.PRODUCTS}${query}`; | ||
| return requestGet(url); | ||
| }; | ||
|
|
||
| // 베스트 top4 상품 조회 | ||
| export const fetchBestProducts = () => { | ||
| const url = `${baseUrl}${ENDPOINTS.PRODUCTS}?page=1&pageSize=4&orderBy=favorite`; | ||
| return requestGet(url); | ||
| }; | ||
|
|
||
| // 상품 상세 조회 | ||
| export const getProductDetail = (productId) => { | ||
| const url = `${baseUrl}${ENDPOINTS.PRODUCTS}/${productId}`; | ||
| return requestGet(url); | ||
| }; | ||
|
|
||
| // 상품 수정 | ||
| export const patchProduct = (productId, data) => { | ||
| const url = `${baseUrl}${ENDPOINTS.PRODUCTS}/${productId}`; | ||
| return requestPatch(url, data); | ||
| }; | ||
|
|
||
| // 상품 삭제 | ||
| export const deleteProduct = (productId) => { | ||
| const url = `${baseUrl}${ENDPOINTS.PRODUCTS}/${productId}`; | ||
| return requestDelete(url); | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| import { safeFetch } from '@/utils/api'; | ||
|
|
||
| export const requestGet = async (url, options = {}) => { | ||
| return safeFetch({ url, options: { method: 'GET', ...options } }); | ||
| }; | ||
|
|
||
| export const requestPost = async (url, data, options = {}) => { | ||
| const isFormData = data instanceof FormData; | ||
|
|
||
| return safeFetch({ | ||
| url, | ||
| options: { | ||
| method: 'POST', | ||
| headers: isFormData ? undefined : { 'Content-Type': 'application/json' }, | ||
| body: isFormData ? data : JSON.stringify(data), | ||
| ...options, | ||
| }, | ||
| }); | ||
| }; | ||
|
|
||
| export const requestPut = async (url, data, options = {}) => { | ||
| return safeFetch({ | ||
| url, | ||
| options: { | ||
| method: 'PUT', | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| body: JSON.stringify(data), | ||
| ...options, | ||
| }, | ||
| }); | ||
| }; | ||
|
|
||
| export const requestPatch = async (url, data, options = {}) => { | ||
| return safeFetch({ | ||
| url, | ||
| options: { | ||
| method: 'PATCH', | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| body: JSON.stringify(data), | ||
| ...options, | ||
| }, | ||
| }); | ||
| }; | ||
|
|
||
| export const requestDelete = async (url, options = {}) => { | ||
| return safeFetch({ url, options: { method: 'DELETE', ...options } }); | ||
| }; |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,18 +1,19 @@ | ||
| // tagHelpers.module.scss로 공통으로 뺐는데 이게 맞는건지 판단 중 | ||
| .tagList { | ||
| display: flex; | ||
| flex-wrap: wrap; | ||
| gap: 0.8rem; | ||
| margin-top: 0.8rem; | ||
| } | ||
|
|
||
| .tag { | ||
| margin-top: 1.4rem; | ||
| padding: 0.5rem 1.2rem 0.5rem 1.6rem; | ||
| background-color: var(--primary-50); | ||
| border-radius: 26px; | ||
| font-size: 1.6rem; | ||
| color: var(--secondary-800); | ||
| display: flex; | ||
| align-items: center; | ||
| gap: 0.8rem; | ||
| } | ||
|
|
||
| // .tag { | ||
| // margin-top: 1.4rem; | ||
| // padding: 0.5rem 1.2rem 0.5rem 1.6rem; | ||
| // background-color: var(--primary-50); | ||
| // border-radius: 26px; | ||
| // font-size: 1.6rem; | ||
| // color: var(--secondary-800); | ||
| // display: flex; | ||
| // align-items: center; | ||
| // gap: 0.8rem; | ||
| // } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,54 @@ | ||||||||
| import { useState } from 'react'; | ||||||||
| import { useToast } from '@/contexts'; | ||||||||
| import { postComment } from '@/api/comment'; | ||||||||
| import { postCommentErrorMessage } from '@/utils/errorMessage'; | ||||||||
| import formStyles from '@/styles/helpers/formHelpers.module.scss'; | ||||||||
| import buttonStyles from '@/styles/helpers/buttonHelpers.module.scss'; | ||||||||
| import styles from './CommentInput.module.scss'; | ||||||||
|
|
||||||||
| const CommentInput = ({ productId, refreshAfterSubmit }) => { | ||||||||
| const { showToast } = useToast(); | ||||||||
| const [content, setContent] = useState(''); | ||||||||
|
|
||||||||
| const handleSubmit = async () => { | ||||||||
| if (!content.trim()) return; | ||||||||
|
Comment on lines
+13
to
+14
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
|
||||||||
|
|
||||||||
| try { | ||||||||
| await postComment(productId, content); | ||||||||
|
|
||||||||
| setContent(''); | ||||||||
| refreshAfterSubmit(); // 등록 후 댓글 목록 새로고침 | ||||||||
| } catch (error) { | ||||||||
| showToast(postCommentErrorMessage(error.status), 'error'); | ||||||||
| } | ||||||||
| }; | ||||||||
|
|
||||||||
| return ( | ||||||||
| <div className={formStyles.inputContainer}> | ||||||||
| <div className={styles.inputContainer}> | ||||||||
| <label htmlFor="content" className={formStyles.labelText}> | ||||||||
| 문의하기 | ||||||||
| </label> | ||||||||
| <textarea | ||||||||
| id="content" | ||||||||
| name="content" | ||||||||
| value={content} | ||||||||
| className={formStyles.textarea} | ||||||||
| rows={4} | ||||||||
| onChange={(e) => setContent(e.target.value)} | ||||||||
| placeholder="개인정보를 공유 및 요청하거나, 명예 훼손, 무단 광고, 불법 정보 유포시 모니터링 후 삭제될 수 있으며, 이에 대한 민형사상 책임은 게시자에게 있습니다." | ||||||||
| /> | ||||||||
| </div> | ||||||||
| <button | ||||||||
| type="button" | ||||||||
| className={`${buttonStyles.primary} ${styles.submitButton}`} | ||||||||
| onClick={handleSubmit} | ||||||||
| disabled={!content.trim()} | ||||||||
| > | ||||||||
| 등록 | ||||||||
| </button> | ||||||||
| </div> | ||||||||
| ); | ||||||||
| }; | ||||||||
|
|
||||||||
| export default CommentInput; | ||||||||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
💊 제안
CommentInput 컴포넌트 내부에서 refreshAfterSubmit라는 이름으로 함수를 받을 필요가 없어보여요.
이러한 이름은 함수명으로는 적절하지만 해당 컴포넌트 내부에서는 그냥 onSubmit 정도로 추상화하는게 더 적절해보입니다~