Skip to content

Commit 7c07255

Browse files
authored
Merge pull request #114 from Imhwitae/React-황휘태-sprint7
[황휘태] sprint7
2 parents 94a802a + 4625775 commit 7c07255

26 files changed

Lines changed: 1119 additions & 36 deletions

README.md

Lines changed: 186 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,189 @@
1-
# React + Vite
1+
# 판다 마켓 - 중고 거래 플랫폼
22

3-
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
3+
## 미션 3 요구사항
44

5-
Currently, two official plugins are available:
5+
### 기본
66

7-
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8-
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
7+
- [x] 랜딩 페이지의 url path는 루트(‘/’) 입니다.
8+
- [x] title은 “판다마켓”으로 설정해 주세요.
9+
- [x] 화면의 너비가 1920px 이상이면 하늘색 배경색은 너비를 꽉 채우도록 채워지고, 내부 요소들의 위치는 고정되고, 여백만 커지도록 해주세요.
10+
- [x] 화면의 너비가 1920px 보다 작아질 때, “판다마켓” 로고의 왼쪽 여백 200px“로그인" 버튼의 오른쪽 여백 200px이 유지되고, 화면의 너비가 작아질수록 두 요소간 거리가 가까워지도록 해주세요.
11+
- [x] 클릭으로 기능이 동작해야 하는 경우, 사용자가 클릭할 수 있는 요소임을 알 수 있도록 cursor: pointer를 설정해 주세요.
12+
- [x] “판다마켓” 클릭 시 루트 페이지(‘/’)로 이동시켜주세요.
13+
- [x] “구경하러 가기" 클릭 시 (“/items”)페이지로 이동시켜주세요.(빈 페이지)
14+
- [x] “로그인”버튼 클릭 시 로그인 페이지(‘/login’)로 이동합니다
15+
- [x] “구경하러가기”버튼 클릭 시(’/items’)로 이동합니다
16+
- [x] 페이스북, 트위터, 유튜브, 인스타그램 아이콘은 클릭 시 각각의 홈페이지로 새로운 창이 열리면서 이동 합니다
17+
- [x] “Privacy Policy”, “FAQ”는 클릭 시 각각 아래 페이지로 이동합니다- Privacy 페이지(‘/privacy’) - FAQ 페이지(‘/faq’)
18+
19+
---
20+
21+
- [x] 아래로 스크롤 해도 상단 네비게이션 바(Global Navigation Bar)가 최상단에 고정됩니다.
22+
- [x] “판다마켓" 클릭 시 루트 페이지(“/”)로 이동합니다. (새로고침)
23+
- [x] 로그인 페이지, 회원가입 페이지 모두 로고 위 상단 여백이 동일합니다.
24+
- [x] SNS 아이콘들은 클릭시 각각 아래 페이지로 이동합니다.- “https://www.google.com/”, “https://www.kakaocorp.com/page/”
25+
- [x] “회원 가입”버튼 클릭 시 “/signup” 페이지로 이동합니다.
26+
27+
---
28+
29+
- [x] 브라우저에 현재 보이는 화면의 영역(viewport) 너비를 기준으로 분기되는 반응형 디자인을 적용합니다.- PC: 1200px 이상- Tablet: 768px 이상 ~ 1199px 이하- Mobile: 375px 이상 ~ 767px 이하\* 375px 미만 사이즈의 디자인은 고려하지 않습니다
30+
- [x] Tablet 사이즈로 작아질 때 “판다마켓” 로고의 왼쪽에 여백 24px, “로그인” 버튼 오른쪽 여백 24px을 유지할 수 있도록 “판다마켓” 로고와 “로그인" 버튼의 간격이 가까워집니다.
31+
- [x] Mobile 사이즈로 작아질 때 “판다마켓” 로고의 왼쪽에 여백 16px, “로그인” 버튼 오른쪽 여백 16px을 유지할 수 있도록 “판다마켓” 로고와 “로그인" 버튼의 간격이 가까워집니다.
32+
- [x] Tablet 사이즈에서 내부 디자인은 PC사이즈와 동일합니다.
33+
- [x] Mobile 사이즈에서 좌우 여백 16px 제외하고 내부 요소들이 너비를 모두 차지합니다.
34+
- [x] Mobile 사이즈에서 내부 요소들의 너비는 기기의 너비가 커지는 만큼 커지지만 400px을 넘지 않습니다.
35+
- [x] Mobile 사이즈에서 좌우 여백 16px 제외하고 내부 요소들이 너비를 모두 차지합니다.
36+
- [x] Mobile 사이즈에서 내부 요소들의 너비는 기기의 너비가 커지는 만큼 커지지만 400px을 넘지 않습니다.
37+
38+
### 심화
39+
40+
- [x] 사용자의 브라우저가 크고 작아짐에 따라 페이지의 요소간 간격, 요소의 크기, font-size 등 모든 크기와 관련된 값이 크고 작아지도록 설정해 보세요.(설정값은 자유입니다)
41+
42+
---
43+
44+
- [x] palette에 있는 color값들을 css 변수로 등록하고 사용합니다.
45+
46+
---
47+
48+
- [x] 페이스북, 카카오톡, 디스코드, 트위터 등 SNS에서 Linkbrary 랜딩 페이지(“/”) 공유 시 좌측 예시와 같은 미리보기를 볼 수 있도록 랜딩 페이지 메타 태그를 설정해 주세요.
49+
- [x] 미리보기에서 제목은 “판다 마켓”, 설명은 “일상의 모든 물건을 거래해보세요”로 설정합니다.
50+
- [x] 주소와 이미지는 자유롭게 설정하세요.
51+
52+
### 주요 변경사항
53+
54+
- Netlify에서 로고 이미지가 보이게 수정했습니다.
55+
56+
### 스크린샷
57+
58+
**메인화면**
59+
| PC | Tablet | Mobile |
60+
| :-: | :----: | :----: |
61+
|![pc_main](https://github.com/user-attachments/assets/ab4254e0-c732-49b6-8eb3-becf313e4a92)|![tablet_main](https://github.com/user-attachments/assets/28e8b861-bf77-47b1-9f60-93267f592650)|![mobile_main](https://github.com/user-attachments/assets/fe76d76f-9b93-4403-8205-ec875e364f7f)|
62+
63+
<br>
64+
65+
**로그인 화면**
66+
| PC | Mobile |
67+
| :-: | :----: |
68+
|![pc_login](https://github.com/user-attachments/assets/aa9ff9df-8eff-4f13-a7e4-e946ad8fe48f)|![mobile_login](https://github.com/user-attachments/assets/8e1662fb-4544-48ce-a791-40e3e5ce0e28)|
69+
70+
<br>
71+
72+
**회원가입 화면**
73+
| PC | Mobile |
74+
| :-: | :----: |
75+
|![join_pc](https://github.com/user-attachments/assets/52788e32-a174-4441-abe1-957bc36094e7)|![join_mobile](https://github.com/user-attachments/assets/6222a188-d431-433c-959a-07c052ff61a5)|
76+
77+
### 멘토에게
78+
79+
- 저는 CSS를 작성할 때 대부분의 단위를 `px`로 사용했는데, `rem`, `vw`와 같은 단위를 사용하는 것이 더 나은지 궁금합니다
80+
> 답변
81+
> [px vs rem vs em 접근성과 관련된 아티클](https://www.joshwcomeau.com/css/surprising-truth-about-pixels-and-accessibility/)
82+
83+
<br>
84+
85+
## 미션 5 요구사항
86+
87+
### 기본
88+
89+
- [x] 중고마켓 페이지 주소는 "/items" 입니다.
90+
- [x] 페이지 주소가 "/items" 일 때 상단 네비게이션 바의 "중고마켓" 버튼의 색상은 "3692FF" 입니다.
91+
- [x] 상단 네비게이션 바는 이전 미션에서 구현한 랜딩 페이지와 동일한 스타일로 만들어주세요
92+
- [x] 전체 상품에서 드롭다운으로 "최신순" 또는 "좋아요순"을 선택해서 정렬할 수 있습니다.
93+
- [ ] "상품 등록하기" 버튼을 누르면 “/additem” 로 이동합니다 ( 빈 페이지 )
94+
- [x] 미디어 쿼리를 사용하여 반응형 view 마다 물품 개수를 다르게 보여줍니다 (서버로 요청하는 값은 동일)
95+
- 베스트 상품
96+
- Desktop : 4개 보이기
97+
- Tablet : 2개 보이기
98+
- Mobile : 1개 보이기
99+
- 전체 상품
100+
- Desktop : 10개 보이기
101+
- Tablet : 6개 보이기
102+
- Mobile : 4개 보이기
103+
104+
### 심화
105+
106+
- [x] 페이지 네이션 기능을 구현합니다.
107+
- [x] 반응형으로 보여지는 물품들의 개수를 다르게 설정할때 서버에 보내는 pageSize값을 적절하게 설정합니다.
108+
109+
### 주요 변경사항
110+
111+
- 스프린트 미션 1부터 4까지의 내용을 React로 변경했습니다.
112+
> form 변경 내용: [React-Hook-form을 이용해 유효성 검사 해보기](https://velog.io/@nudge0613/React-Hook-Form%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%B4-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%EC%9C%A0%ED%9A%A8%EC%84%B1-%EA%B2%80%EC%82%AC-%ED%95%98%EA%B8%B0)
113+
114+
### 스크린샷
115+
116+
| PC | Tablet | Mobile |
117+
| :-------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------: |
118+
| <img width="1413" height="1456" alt="localhost_5173_items" src="https://github.com/user-attachments/assets/0e017351-f79f-4428-be83-ef06eb510031" /> | <img width="2274" height="3022" alt="localhost_5173_items (1)" src="https://github.com/user-attachments/assets/7268b74d-0721-43a4-9a97-d2893df28540" /> | <img width="750" height="2830" alt="localhost_5173_items (2)" src="https://github.com/user-attachments/assets/17ae2721-6c04-40dd-99d6-c25902d8cd2e" /> |
119+
120+
<br>
121+
122+
## 미션 6 요구사항
123+
124+
### 기본
125+
126+
- [x] 상품 등록 페이지 주소는 “/additem” 입니다.
127+
- [x] 페이지 주소가 “/additem” 일때 상단네비게이션바의 '중고마켓' 버튼의 색상은 “3692FF”입니다.
128+
- [x] 상품 이미지는 최대 한개 업로드가 가능합니다.
129+
- [x] 각 input의 placeholder 값을 정확히 입력해주세요.
130+
- [x] 이미지를 제외하고 input 에 모든 값을 입력하면 ‘등록' 버튼이 활성화 됩니다.
131+
- [ ] API를 통한 상품 등록은 추후 미션에서 적용합니다.
132+
133+
### 심화
134+
135+
- [x] 이미지 안의 X 버튼을 누르면 이미지가 삭제됩니다.
136+
- [x] 추가된 태그 안의 X 버튼을 누르면 해당 태그는 삭제됩니다.
137+
138+
### 주요 변경사항
139+
140+
- styled component를 통해 스타일링
141+
142+
### 스크린샷
143+
144+
| PC | Tablet | Mobile |
145+
| :---------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------: |
146+
| <img width="1920" height="1655" alt="localhost_5173_additem" src="https://github.com/user-attachments/assets/e078e0f9-3de5-4045-930a-ffb997db412f" /> | <img width="1964" height="3136" alt="localhost_5173_additem (1)" src="https://github.com/user-attachments/assets/b6041614-7825-4c2c-b7da-01d56d038684" /> | <img width="938" height="3136" alt="localhost_5173_additem (2)" src="https://github.com/user-attachments/assets/af508c63-5fcb-4140-9afd-3c0a49bbf58e" /> |
147+
148+
### 멘토에게
149+
150+
- styled component를 사용해서 스타일링을 했는데 한 컴포넌트의 코드가 너무 길어지는 느낌입니다.
151+
스타일은 따로 빼놓는게 나을까요?
152+
153+
<br>
154+
155+
## 미션 7 요구사항
156+
157+
### 기본
158+
159+
- [x] 상품 상세 페이지 주소는 “items/{productId}” 입니다.
160+
- [x] response로 받은 아래의 데이터로 화면을 구현합니다.
161+
- favoriteCount : 하트 개수
162+
- images : 상품 이미지
163+
- tags : 상품태그
164+
- name : 상품 이름
165+
- description : 상품 설명
166+
- [x] 목록으로 돌아가기 버튼을 클릭하면 중고마켓 페이지 주소인 "/items"로 이동합니다.
167+
- [x] 문의하기에 내용을 입력하면 등록 버튼의 색상은 “3692FF”로 변합니다.
168+
- [x] response 로 받은 아래의 데이터로 화면을 구현합니다.
169+
- image : 작성자 이미지
170+
- nickname : 작성자 닉네임
171+
- content : 작성자가 남긴 문구
172+
- description : 상품 설명
173+
- updatedAt : 문의글 마지막 업데이트 시간
174+
175+
### 심화
176+
177+
- [x] 모든 버튼에 자유롭게 Hover효과를 적용하세요.
178+
179+
### 주요 변경사항
180+
181+
### 스크린샷
182+
183+
| PC | Tablet | Mobile |
184+
| :---------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------: |
185+
| <img width="1920" height="1655" alt="localhost_5173_additem" src="https://github.com/user-attachments/assets/e078e0f9-3de5-4045-930a-ffb997db412f" /> | <img width="1964" height="3136" alt="localhost_5173_additem (1)" src="https://github.com/user-attachments/assets/b6041614-7825-4c2c-b7da-01d56d038684" /> | <img width="938" height="3136" alt="localhost_5173_additem (2)" src="https://github.com/user-attachments/assets/af508c63-5fcb-4140-9afd-3c0a49bbf58e" /> |
186+
187+
### 멘토에게
188+
189+
Copyright 2025 코드잇 Inc. All rights reserved.

src/App.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import AuthLayout from "./layout/AuthLayout";
77
import ItemsLayout from "./layout/ItemsLayout";
88
import Items from "./pages/items/Items";
99
import AddItem from "./pages/items/AddItem";
10+
import ItemDetail from "./pages/items/ItemDetail";
1011

1112
function App() {
1213
return (
@@ -27,6 +28,7 @@ function App() {
2728
<Route element={<ItemsLayout />}>
2829
<Route path="items" element={<Items />} />
2930
<Route path="additem" element={<AddItem />} />
31+
<Route path="/items/:productId" element={<ItemDetail />} />
3032
</Route>
3133
</Routes>
3234
</>

src/assets/icons/ic_back.svg

Lines changed: 4 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading
6.1 KB
Loading

src/components/Inquiry.jsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import {
2+
BackButton,
3+
BackButtonWrapper,
4+
InquiryTitle,
5+
} from "../styles/components/InquiryStyles";
6+
import { requestInquiryLists } from "../services/inquiryApi";
7+
import { useNavigate } from "react-router";
8+
import icBack from "../assets/icons/ic_back.svg";
9+
import useService from "../hooks/useService";
10+
import InquiryWriteArea from "./InquiryWriteArea";
11+
import InquiryList from "../pages/components/ItemDetail/InquiryList";
12+
13+
export default function Inquiry({ id }) {
14+
const navigate = useNavigate();
15+
16+
/**
17+
* 문의 내역을 가져온다.
18+
*/
19+
const { data, isLoading } = useService(() => requestInquiryLists(id));
20+
21+
return (
22+
<>
23+
<InquiryTitle>문의하기</InquiryTitle>
24+
<InquiryWriteArea />
25+
{!isLoading ? <InquiryList data={data} /> : <div>로딩중</div>}
26+
<BackButtonWrapper>
27+
<BackButton onClick={() => navigate(-1)}>
28+
목록으로 돌아가기
29+
<img src={icBack} alt="뒤로가기 이미지" />
30+
</BackButton>
31+
</BackButtonWrapper>
32+
</>
33+
);
34+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { useState } from "react";
2+
import usePost from "../hooks/usePost";
3+
import {
4+
InquirySubmitButton,
5+
InquiryTextArea,
6+
} from "../styles/components/InquiryStyles";
7+
8+
/**
9+
* 문의 내역 작성 공간
10+
*/
11+
export default function InquiryWriteArea() {
12+
const [isActive, setIsActive] = useState(false);
13+
const [inquiryContent, setInquiryContent] = useState("");
14+
15+
const onChangeWrite = (e) => {
16+
if (e.target.value) {
17+
setIsActive(true);
18+
} else {
19+
setIsActive(false);
20+
}
21+
22+
setInquiryContent(e.target.value);
23+
};
24+
25+
const onClickUploadInquiry = () => {
26+
let data = {
27+
productId: id,
28+
Inquiry: {
29+
content: inquiryContent,
30+
},
31+
};
32+
33+
const { data: success } = usePost(requestPostInquiry(data));
34+
35+
if (success) {
36+
location.reload(true);
37+
} else {
38+
alert("등록에 실패했습니다.");
39+
}
40+
};
41+
42+
return (
43+
<div style={{ textAlign: "right", marginBottom: "20px" }}>
44+
<InquiryTextArea
45+
onChange={onChangeWrite}
46+
placeholder="개인정보를 공유 및 요청하거나, 명예 훼손, 무단 광고, 불법 정보 유포시 모니터링 후 삭제될 수 있으며, 이에 대한 민형사상 책임은 게시자에게 있습니다."
47+
></InquiryTextArea>
48+
<InquirySubmitButton
49+
type={isActive ? "submit" : "button"}
50+
isActive={isActive}
51+
onClick={onClickUploadInquiry}
52+
>
53+
등록
54+
</InquirySubmitButton>
55+
</div>
56+
);
57+
}

0 commit comments

Comments
 (0)