Skip to content

Commit

Permalink
[김수영] sprint6 (#91)
Browse files Browse the repository at this point in the history
* feat: header

* feat : market page best item list

* feat: market page all item list

* feat:product img input

* feat: product name,description,price,tag input

* feat:additem page responsive
  • Loading branch information
swim-kim authored Sep 19, 2024
1 parent fd1c5e6 commit e791bf7
Show file tree
Hide file tree
Showing 21 changed files with 666 additions and 24 deletions.
17 changes: 15 additions & 2 deletions .github/workflows/delete-merged-branch-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,20 @@ jobs:
delete-branch:
runs-on: ubuntu-latest
steps:
- name: delete branch
- name: Checkout repository
uses: actions/checkout@v3

- name: Check if branch exists
id: check_branch
run: |
if git show-ref --verify --quiet refs/heads/${{ github.head_ref }}; then
echo "branch_exists=true" >> $GITHUB_ENV
else
echo "branch_exists=false" >> $GITHUB_ENV
fi
- name: Delete branch
if: env.branch_exists == 'true'
uses: SvanBoxel/delete-merged-branch@main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
7 changes: 5 additions & 2 deletions src/Router.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Market from './pages/Market/Market';
import AddItem from './pages/AddItem/AddItem';

function Router() {
return (
<BrowserRouter>
<Routes>
<Route path="/item" element={<Market />}/>
<Route path="/items" element={<Market />}/>
<Route path="/addItem" element={<AddItem />} />
</Routes>
</BrowserRouter>
)
}

export default Router
export default Router;
24 changes: 23 additions & 1 deletion src/api/itemApi.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
const BASE_URL = 'https://panda-market-api.vercel.app';

export async function getProducts(params = {}) {

const query = new URLSearchParams(params).toString();
const allowedParams = ["orderBy", "pageSize", "page", "keyword"];
const invalidParams = Object.keys(params)
.filter(key => !allowedParams.includes(key));

if (invalidParams.length > 0) {
console.error(`Invalid parameters detected: ${invalidParams.join(", ")}`);
}

try {
const response = await fetch(
`https://panda-market-api.vercel.app/products?${query}`
`${BASE_URL}/products?${query}`
);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
Expand All @@ -16,3 +26,15 @@ export async function getProducts(params = {}) {
}
}

export async function createFood(formData) {
const response = await fetch(`${BASE_URL}/products`, {
method: 'POST',
body: formData,
});
if (!response.ok) {
throw new Error('데이터를 생성하는데 실패했습니다');
}
const body = await response.json();
return body;
}

Binary file added src/assets/images/plusicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/xicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 21 additions & 8 deletions src/components/Header/Header.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from 'react'
import React from 'react';
import { Link, NavLink, useLocation } from 'react-router-dom';
import PandaLogo from "../../assets/images/pandalogo.png";
import ProfileImg from "../../assets/images/profile.png";
import { Link, NavLink } from 'react-router-dom';
import './Header.css';

function header() {
function Header() {
const location = useLocation();

return (
<header>
<div className="header-container">
Expand All @@ -13,15 +15,26 @@ function header() {
<img className="panda-logo" src={PandaLogo} alt="판다마켓로고" />
</Link>
<div className="nav-container">
<NavLink to="/community" activeClassName="active">자유게시판</NavLink>
<NavLink to="/item" activeClassName="active">중고마켓</NavLink>
<NavLink
to="/community"
className={({ isActive }) => (isActive ? 'active' : '')}
>
자유게시판
</NavLink>
<NavLink
to="/items"
className={({ isActive }) => (
location.pathname === '/items' || location.pathname === '/addItem' ? 'active' : ''
)}
>
중고마켓
</NavLink>
</div>
</div>
<img className="profile-img" src={ProfileImg} alt="프로필 이미지" />
</div>

</header>
)
);
}

export default header
export default Header;
67 changes: 67 additions & 0 deletions src/pages/AddItem/AddItem.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
.addItem {
width:100%;
display:flex;
justify-content: center;
align-items: center;
margin-top:29px;
}
.content-container {
max-width:1200px;
width:100%;
height:100%;
display: flex;
flex-direction: column;
gap:32px;
}
.title {
width:109px;
color: var(--Secondary-800, #1F2937);
font-size: 20px;
font-weight: 700;
line-height: 32px;
}
.title-container {
height:42px;
display:flex;
justify-content: space-between;
align-items: center;
width:100%;

}
form {
display:flex;
flex-direction: column;
gap:32px;
}
.submit-button {
width:74px;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
border-radius: 8px;
border:none;
background:#3692FF;
color: var(--Cool-Gray-100, #F3F4F6);
font-size: 16px;
font-weight: 600;
line-height: 26px;
cursor:pointer;
}
.submit-button:disabled{
background: var(--Cool-Gray-400, #9CA3AF);
}

/* tablet */
@media (max-width:1199px) {
.content-container {
max-width:744px;
}
}

/* mobile */
@media (max-width:767px) {
.content-container {
max-width: 375px;
}
}
87 changes: 87 additions & 0 deletions src/pages/AddItem/AddItem.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React, { useEffect, useState } from 'react'
import Header from '../../components/Header/Header';
import './AddItem.css';
import ProductImg from './components/ProductImg/ProductImg';
import ProductName from './components/ProductName/ProductName';
import ProductDescription from './components/ProductDescription/ProductDescription';
import ProductPrice from './components/ProductPrice/ProductPrice';
import ProductTag from './components/ProductTag/ProductTag';

function AddItem() {
const [isValid, setIsValid] = useState(false);
const [values, setValues] = useState({
imgFile:null,
name:'',
description:'',
price:'',
tags:[],
})

const isFormValid = (values) => {
return (values.name.trim() !== '' &&
values.description.trim() !== '' &&
values.price > 0 &&
values.tags.length > 0);
}
const handleSubmit = (e) => {
e.preventDefault();
if(!isFormValid(values)){
return;
}
console.log(values);
}
const handleChange = (name, value) => {
setValues((prevValues) => ({
...prevValues,
[name]: value,
}));
};

useEffect(() => {
setIsValid(isFormValid(values));
},[values]);

return (
<>
<Header />
<div className="addItem">
<div className="content-container">
<form onSubmit={handleSubmit}>
<div className="title-container">
<div className="title">상품 등록하기</div>
<button type="submit" className="submit-button" disabled={!isValid}>등록</button>
</div>
<ProductImg
name="imgFile"
value={values.imgFile}
onChange={handleChange}
/>
<ProductName
name="name"
value={values.name}
onChange={handleChange}
/>
<ProductDescription
name="description"
value={values.description}
onChange={handleChange}
/>
<ProductPrice
name="price"
value={values.price}
onChange={handleChange}
/>
<ProductTag
name="tags"
value={values.tags}
onChange={handleChange}
/>
</form>
</div>
</div>
</>

)
}

export default AddItem;
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
.description-container {
display: flex;
gap:16px;
flex-direction: column;
}
.description {
color: var(--Secondary-800, #1F2937);
font-size: 18px;
font-weight: 700;
line-height: 26px;
}
.description-input {
height: 282px;
padding: 24px 16px;
border:none;
border-radius: 12px;
background: var(--Cool-Gray-100, #F3F4F6);

}
.description-input::placeholder {
color: var(--Secondary-400, #9CA3AF);
font-size: 16px;
font-weight: 400;
line-height: 26px;

align-items: top;
}

@media (max-width:1199px) {

}

/* mobile */
@media (max-width:767px) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import './ProductDescription.css';

function ProductDescription({ name, value, onChange }) {
const handleChange = (e) => {
onChange(name, e.target.value);
};
return (
<div className='description-container'>
<label className='description'>상품 소개</label>
<textarea
className='description-input'
name={name}
value={value}
placeholder="상품 소개를 입력해주세요"
onChange={handleChange}
></textarea>
</div>
)
}

export default ProductDescription
Loading

0 comments on commit e791bf7

Please sign in to comment.