Skip to content

Commit

Permalink
React 김주동 sprint7 (#97)
Browse files Browse the repository at this point in the history
* First commit Sprint Mission5 on React

* Sprint mission 6 commit.

* Sprint Mission 6 Update 1

* update sprint mission 6

* Sprint mission 6 update commit.

* delete .bak files

* Update Comments

* modify ItemComment
  • Loading branch information
joodongkim authored Sep 23, 2024
1 parent d48b01a commit 4f9c678
Show file tree
Hide file tree
Showing 41 changed files with 1,859 additions and 370 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
# production
/build

# backup
/backups
.bak

# misc
.DS_Store
.env.local
Expand All @@ -21,3 +25,4 @@
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.vercel
473 changes: 316 additions & 157 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
{
"name": "fe10-sprint-mission5",
"name": "fe10-sprint-mission7",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"date-fns": "^3.6.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.22.3",
"react-scripts": "5.0.1",
"react-spinners": "^0.13.8",
"styled-components": "^6.1.8",
"web-vitals": "^2.1.4"
},
"scripts": {
Expand Down
39 changes: 0 additions & 39 deletions package.json.bak

This file was deleted.

2 changes: 1 addition & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="keywords" content="Codeit - FE10 Sprint Mission 5">
<meta name="keywords" content="Codeit - FE10 Sprint Mission 7">
<meta name="author" content="[email protected]">
<meta property="og:type" content="website" />
<meta property="og:title" content="판다마켓" />
Expand Down
3 changes: 3 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@ import MarketPage from "./pages/MarketPage/MarketPage";
import AddItemPage from "./pages/AddItemPage/AddItemPage";
import CommunityFeedPage from "./pages/CommunityFeedPage/CommunityFeedPage";
import Header from "./components/Layout/Header";
import ItemPage from "./pages/ItemPage/ItemPage";

function App() {
return (
<BrowserRouter>
<Header />

<div className="withHeader">
<Routes>
<Route index element={<HomePage />} />
<Route path="login" element={<LoginPage />} />
<Route path="items" element={<MarketPage />} />
<Route path="items/:productId" element={<ItemPage />} />
<Route path="additem" element={<AddItemPage />} />
<Route path="community" element={<CommunityFeedPage />} />
</Routes>
Expand Down
41 changes: 41 additions & 0 deletions src/api/itemApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,44 @@ export async function getProducts(params = {}) {
throw error;
}
}

export async function getProductDetail(productId) {
if (!productId) {
throw new Error("Invalid product ID");
}

try {
const response = await fetch(
`https://panda-market-api.vercel.app/products/${productId}`
);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const body = await response.json();
return body;
} catch (error) {
console.error("Failed to fetch product detail:", error);
throw error;
}
}

export async function getProductComments({ productId, params }) {
if (!productId) {
throw new Error("Invalid product ID");
}

try {
const query = new URLSearchParams(params).toString();
const response = await fetch(
`https://panda-market-api.vercel.app/products/${productId}/comments?${query}`
);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const body = await response.json();
return body;
} catch (error) {
console.error("Failed to fetch product comments:", error);
throw error;
}
}
4 changes: 4 additions & 0 deletions src/assets/images/icons/ic_back.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/assets/images/icons/ic_kebab.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/assets/images/icons/ic_plus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/assets/images/icons/ic_x.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions src/assets/images/ui/empty-comments.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions src/assets/images/ui/ic_profile.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/Layout/Header.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
gap: 8px;
font-weight: bold;
font-size: 16px;
color: #4b5563;
color: var(--gray-600);
}

.globalHeader nav ul li a:hover {
Expand Down
41 changes: 25 additions & 16 deletions src/components/Layout/Header.jsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,50 @@
import React from 'react'
import Logo from '../../assets/images/logo/logo.svg'
import { Link, NavLink } from 'react-router-dom'
import './Header.css'
import React from "react";
import Logo from "../../assets/images/logo/logo.svg";
import { Link, NavLink, useLocation } from "react-router-dom";
import "./Header.css";

function getLinkStyle ({ isActive }) {
return { color: isActive ? 'var(--blue)' : undefined }
function getLinkStyle({ isActive }) {
return { color: isActive ? "var(--blue)" : undefined };
}

function Header () {
function Header() {
const location = useLocation(); // 현재 경로 정보

return (
<header className='globalHeader'>
<div className='headerLeft'>
<Link to='/' className='headerLogo' aria-label='홈으로 이동'>
<img src={Logo} alt='판다마켓 로고' width='153' />
<header className="globalHeader">
<div className="headerLeft">
<Link to="/" className="headerLogo" aria-label="홈으로 이동">
<img src={Logo} alt="판다마켓 로고" width="153" />
</Link>

<nav>
<ul>
<li>
<NavLink to='/community' style={getLinkStyle}>
<NavLink to="/community" style={getLinkStyle}>
자유게시판
</NavLink>
</li>
<li>
<NavLink to='/items' style={getLinkStyle}>
<NavLink
to="/items"
style={({ isActive }) =>
location.pathname === "/additem" || isActive
? { color: "var(--blue)" }
: {}
}
>
중고마켓
</NavLink>
</li>
</ul>
</nav>
</div>

<Link to='/login' className='loginLink button'>
<Link to="/login" className="loginLink button">
로그인
</Link>
</header>
)
);
}

export default Header
export default Header;
27 changes: 27 additions & 0 deletions src/components/UI/DeleteButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from "react";
import styled from "styled-components";
import { ReactComponent as CloseIcon } from "../../assets/images/icons/ic_x.svg";

const Button = styled.button`
background-color: ${({ theme }) => theme.colors.gray[400]};
width: 20px;
height: 20px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
&:hover {
background-color: ${({ theme }) => theme.colors.blue.primary};
}
`;

function DeleteButton({ onClick, label }) {
return (
<Button aria-label={`${label} 삭제`} onClick={onClick}>
<CloseIcon />
</Button>
);
}

export default DeleteButton;
33 changes: 33 additions & 0 deletions src/components/UI/DropdownMenu.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
.sortButtonWrapper {
position: relative;
}

.sortDropdownTriggerButton {
border: 1px solid var(--gray-200);
border-radius: 12px;
padding: 9px;
margin-left: 8px;
}

.dropdownMenu {
position: absolute;
top: 110%;
right: 0;
background: #fff;
border-radius: 8px;
border: 1px solid var(--gray-200);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
z-index: 99;
}

.dropdownItem {
padding: 12px 44px;
border-bottom: 1px solid var(--gray-200);
font-size: 16px;
color: var(--gray-800);
cursor: pointer;
}

.dropdownItem:last-child {
border-bottom: none;
}
43 changes: 43 additions & 0 deletions src/components/UI/DropdownMenu.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React, { useState } from "react";
import "./DropdownMenu.css";
import { ReactComponent as SortIcon } from "../../assets/images/icons/ic_sort.svg";

function DropdownMenu({ onSortSelection }) {
const [isDropdownVisible, setIsDropdownVisible] = useState(false);

const toggleDropdown = () => {
setIsDropdownVisible(!isDropdownVisible);
};

return (
<div className="sortButtonWrapper">
<button className="sortDropdownTriggerButton" onClick={toggleDropdown}>
<SortIcon />
</button>

{isDropdownVisible && (
<div className="dropdownMenu">
<div
className="dropdownItem"
onClick={() => {
onSortSelection("recent");
setIsDropdownVisible(false);
}}
>
최신순
</div>
<div
className="dropdownItem"
onClick={() => {
onSortSelection("favorite");
setIsDropdownVisible(false);
}}
>
인기순
</div>
</div>
)}
</div>
);
}
export default DropdownMenu;
Loading

0 comments on commit 4f9c678

Please sign in to comment.