diff --git a/public/images/payment/paymentBankBook.svg b/public/images/payment/paymentBankBook.svg new file mode 100644 index 0000000..9386f1a --- /dev/null +++ b/public/images/payment/paymentBankBook.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/public/images/payment/paymentCard.svg b/public/images/payment/paymentCard.svg new file mode 100644 index 0000000..49c0ad6 --- /dev/null +++ b/public/images/payment/paymentCard.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/payment/paymentPhone.svg b/public/images/payment/paymentPhone.svg new file mode 100644 index 0000000..d14caad --- /dev/null +++ b/public/images/payment/paymentPhone.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/Images.jsx b/src/components/Images.jsx index 1509a17..51b0dd3 100644 --- a/src/components/Images.jsx +++ b/src/components/Images.jsx @@ -3,10 +3,9 @@ export const images = { cameraIcon: '/images/common/cameraIcon.svg', loginDogCat: '/images/common/loginDogCat.svg', logo: '/images/common/logo.svg', - kakaobtn:'/images/common/kakaobtn.svg', + kakaobtn: '/images/common/kakaobtn.svg', cancel: '/images/common/cancelButton.svg', - // community categoryAll: '/images/community/categoryAll.svg', categoryAnonymity: '/images/community/categoryAnonymity.svg', @@ -29,23 +28,21 @@ export const images = { // mypage - alert: "/images/myPage/alert.svg", - blockHand: "/images/myPage/blockHand.svg", - bogwan: "/images/myPage/bogwan.svg", - calendar: "/images/myPage/calendar.svg", - hide: "/images/myPage/hide.svg", - imseeJeojang: "/images/myPage/imseeJeojang.svg", - myActivity: "/images/myPage/myActivity.svg", - bag: "/images/myPage/bag.svg", - coupon: "/images/myPage/coupon.svg", - missing: "/images/myPage/missing.svg", - paw: "/images/myPage/paw.svg", - point:"/images/myPage/point.svg", - review:"/images/myPage/review.svg", - mypagecat:"/images/myPage/mypagecat.svg", - dogprofile:"/images/myPage/dogprofile.svg", - - + alert: '/images/myPage/alert.svg', + blockHand: '/images/myPage/blockHand.svg', + bogwan: '/images/myPage/bogwan.svg', + calendar: '/images/myPage/calendar.svg', + hide: '/images/myPage/hide.svg', + imseeJeojang: '/images/myPage/imseeJeojang.svg', + myActivity: '/images/myPage/myActivity.svg', + bag: '/images/myPage/bag.svg', + coupon: '/images/myPage/coupon.svg', + missing: '/images/myPage/missing.svg', + paw: '/images/myPage/paw.svg', + point: '/images/myPage/point.svg', + review: '/images/myPage/review.svg', + mypagecat: '/images/myPage/mypagecat.svg', + dogprofile: '/images/myPage/dogprofile.svg', // walk walkMap: '/images/walk/walkMap.svg', @@ -64,4 +61,9 @@ export const images = { carouselImage6: '/images/carousel/carouselImage6.svg', carouselImage7: '/images/carousel/carouselImage7.svg', carouselImage8: '/images/carousel/carouselImage8.svg', + + // payment + paymentBankBook: '/images/payment/paymentBankBook.svg', + paymentCard: '/images/payment/paymentCard.svg', + paymentPhone: '/images/payment/paymentPhone.svg', }; diff --git a/src/components/common/MainNav.jsx b/src/components/common/MainNav.jsx index 9d023ad..070808c 100644 --- a/src/components/common/MainNav.jsx +++ b/src/components/common/MainNav.jsx @@ -2,8 +2,8 @@ import { useState, useEffect } from 'react'; import styled from 'styled-components'; import { HiOutlineShoppingCart } from 'react-icons/hi'; import { FaRegUserCircle, FaRegBell } from 'react-icons/fa'; -import { PiDogBold } from 'react-icons/pi'; -import { Link,useNavigate,useParams } from 'react-router-dom'; +import { Link, useNavigate } from 'react-router-dom'; +import { images } from '../Images'; const MainNav = () => { const [isScrolled, setIsScrolled] = useState(false); @@ -19,7 +19,6 @@ const MainNav = () => { } }, [location.pathname]); - useEffect(() => { const handleScroll = () => { setIsScrolled(window.scrollY > 0); @@ -44,13 +43,13 @@ const MainNav = () => { { icon: , link: '/shoppingCart' }, ]; - - return ( <> - 발바닥천국 + + 로고 + {icons.map((item, index) => ( @@ -107,7 +106,10 @@ const AnimalWrap = styled.div` `; const AnimalName = styled.div` - margin-left: 4px; + margin-left: 5px; + img { + width: 90px; + } `; const NavIconWrap = styled.div` diff --git a/src/pages/CommunityPage/CommunityDetail.jsx b/src/pages/CommunityPage/CommunityDetail.jsx index b491a7e..ab23bb0 100644 --- a/src/pages/CommunityPage/CommunityDetail.jsx +++ b/src/pages/CommunityPage/CommunityDetail.jsx @@ -1,18 +1,18 @@ -import { useEffect, useState } from "react"; -import { FiHeart } from "react-icons/fi"; -import { IoChatbubbleEllipsesOutline } from "react-icons/io5"; -import { VscAccount } from "react-icons/vsc"; -import { useParams } from "react-router-dom"; -import styled from "styled-components"; -import axios from "../../apis/AxiosInstance"; +import { useEffect, useState } from 'react'; +import { FiHeart } from 'react-icons/fi'; +import { IoChatbubbleEllipsesOutline } from 'react-icons/io5'; +import { VscAccount } from 'react-icons/vsc'; +import { useParams } from 'react-router-dom'; +import styled from 'styled-components'; +import axios from '../../apis/AxiosInstance'; const CommunityDetail = () => { const { no } = useParams(); // %% URL에서 글 번호(no)를 가져옴 %% const [itemDetail, setItemDetail] = useState([]); const [comments, setComments] = useState([]); - const [newComment, setNewComment] = useState(""); + const [newComment, setNewComment] = useState(''); const [users, setUsers] = useState({}); - const [itemUserNickname, setItemUserNickname] = useState(""); + const [itemUserNickname, setItemUserNickname] = useState(''); const [loading, setLoading] = useState(true); // 로딩 상태 관리 useEffect(() => { @@ -21,13 +21,13 @@ const CommunityDetail = () => { // 나눔 상세 가져오기 const itemResponse = await axios.get(`/communities/${no}`); setItemDetail(itemResponse.data); - console.log("나눔 상세 :", itemResponse.data); + console.log('나눔 상세 :', itemResponse.data); // 작성자의 닉네임 가져오기 const userResponse = await axios.get(`/user/${itemResponse.data.user}`); setItemUserNickname(userResponse.data.nickname); } catch (error) { - console.error("Error fetching item or user data:", error); + console.error('Error fetching item or user data:', error); } }; @@ -35,25 +35,21 @@ const CommunityDetail = () => { try { // 댓글 목록 가져오기 const commentsResponse = await axios.get(`/communityComments`); - const relevantComments = commentsResponse.data.filter( - (item) => item.post === parseInt(no) - ); + const relevantComments = commentsResponse.data.filter(item => item.post === parseInt(no)); setComments(relevantComments); - console.log("댓글 목록 :", relevantComments); + console.log('댓글 목록 :', relevantComments); // 댓글 작성자들의 유저 정보 가져오기 - const userIds = [...new Set(relevantComments.map((item) => item.user))]; - const userResponses = await Promise.all( - userIds.map((userId) => axios.get(`/user/${userId}`)) - ); + const userIds = [...new Set(relevantComments.map(item => item.user))]; + const userResponses = await Promise.all(userIds.map(userId => axios.get(`/user/${userId}`))); const userMap = {}; - userResponses.forEach((response) => { + userResponses.forEach(response => { userMap[response.data.userId] = response.data.nickname; }); setUsers(userMap); } catch (error) { - console.error("Error fetching comments or user data:", error); + console.error('Error fetching comments or user data:', error); } finally { setLoading(false); // 모든 로딩 완료 후 로딩 상태 해제 } @@ -72,43 +68,41 @@ const CommunityDetail = () => { ...itemDetail, good: updatedGood, }) - .then((response) => { - console.log("좋아요 업데이트:", response.data); - setItemDetail((prevDetail) => ({ ...prevDetail, good: updatedGood })); + .then(response => { + console.log('좋아요 업데이트:', response.data); + setItemDetail(prevDetail => ({ ...prevDetail, good: updatedGood })); }) - .catch((error) => { - console.error("좋아요 업데이트 실패:", error); + .catch(error => { + console.error('좋아요 업데이트 실패:', error); }); }; // 댓글 등록 - const handleCommentSubmit = (e) => { + const handleCommentSubmit = e => { e.preventDefault(); - const userId = localStorage.getItem("userId"); + const userId = localStorage.getItem('userId'); axios - .post("/communityComments", { + .post('/communityComments', { post: no, user: userId, comment: newComment, }) - .then((response) => { - console.log("댓글 등록 성공:", response.data); - setNewComment(""); + .then(response => { + console.log('댓글 등록 성공:', response.data); + setNewComment(''); return axios.get(`/communityComments`); }) - .then((response) => { - const relevantComments = response.data.filter( - (item) => item.post === parseInt(no) - ); + .then(response => { + const relevantComments = response.data.filter(item => item.post === parseInt(no)); setComments(relevantComments); }) - .catch((error) => { - console.error("댓글 등록 실패:", error); + .catch(error => { + console.error('댓글 등록 실패:', error); }); }; // 댓글 입력 핸들러 - const handleCommentChange = (e) => { + const handleCommentChange = e => { setNewComment(e.target.value); }; @@ -121,7 +115,7 @@ const CommunityDetail = () => { - 작성자: {itemUserNickname || "로딩 중..."} + 작성자: {itemUserNickname || '로딩 중...'} 제목: {itemDetail.title} @@ -136,26 +130,20 @@ const CommunityDetail = () => { {comments.length}
- - {itemDetail.price ? ( - `${itemDetail.price.toLocaleString()}원` - ) : ( - <나눔>나눔 - )} - + {itemDetail.price ? `${itemDetail.price.toLocaleString()}원` : <나눔>나눔}
작성글: {itemDetail.contents} - {comments.map((item) => ( + {comments.map(item => (
- 작성자: {users[item.user] || "로딩 중..."} + 작성자: {users[item.user] || '로딩 중...'} - {new Date(item.createdAt).toLocaleDateString("ko-KR", { - timeZone: "Asia/Seoul", + {new Date(item.createdAt).toLocaleDateString('ko-KR', { + timeZone: 'Asia/Seoul', })} @@ -194,7 +182,7 @@ const ListImg = styled.img` background-color: #d9d9d9; border-radius: 10px; flex-shrink: calc(); /* 이미지 크기를 고정 */ - background-image: url(${(props) => props.src}); /* 이미지 URL 설정 */ + background-image: url(${props => props.src}); /* 이미지 URL 설정 */ background-size: cover; /* 이미지를 채우도록 설정 */ background-position: center; /* 이미지 중앙 정렬 */ `; @@ -308,7 +296,7 @@ const Comment = styled.div` margin-top: 5px; background: #ffffff; padding: 10px; - border-radius: 10px; + border-radius: 8px; box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1); line-height: 1.5; `; @@ -318,8 +306,7 @@ const CommentFrom = styled.form` display: flex; justify-content: flex-end; bottom: 0px; - margin-top: 10px; - margin-bottom: 70px; + margin: 20px 0 80px; padding: 0 20px; `; @@ -330,7 +317,7 @@ const CommentCC = styled.input` border-style: none; outline: none; background-color: #f0f0f0; - border-radius: 20px; + border-radius: 8px; padding: 0px 15px; font-size: 14px; transition: background-color 0.3s ease; @@ -351,7 +338,7 @@ const CommentSubmit = styled.button` background-color: #ff6e00; color: white; border: none; - border-radius: 15px; + border-radius: 8px; transition: background-color 0.3s ease; &:hover { background-color: #e65c00; diff --git a/src/pages/CommunityPage/CommunityList.jsx b/src/pages/CommunityPage/CommunityList.jsx index ec73a1d..fcca102 100644 --- a/src/pages/CommunityPage/CommunityList.jsx +++ b/src/pages/CommunityPage/CommunityList.jsx @@ -1,10 +1,11 @@ -import { useEffect, useState } from "react"; -import { useNavigate } from "react-router-dom"; -import styled from "styled-components"; -import axios from "../../apis/AxiosInstance"; -import { images } from "../../components/Images"; -import { FcLike } from "react-icons/fc"; -import { IoChatbubbleEllipsesOutline } from "react-icons/io5"; +import { useEffect, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import styled from 'styled-components'; +import axios from '../../apis/AxiosInstance'; +import { images } from '../../components/Images'; +import { FcLike } from 'react-icons/fc'; +import { FaSearch } from 'react-icons/fa'; +import { IoChatbubbleEllipsesOutline } from 'react-icons/io5'; const CommunityList = () => { const navigate = useNavigate(); @@ -12,53 +13,55 @@ const CommunityList = () => { const [filteredCommunityList, setFilteredCommunityList] = useState([]); const [comments, setComments] = useState([]); const [userNicknames, setUserNicknames] = useState({}); - const [activeCategory, setActiveCategory] = useState("전체"); + const [activeCategory, setActiveCategory] = useState('전체'); + const [searchQuery, setSearchQuery] = useState(''); + const category = [ - { src: images.categoryAll, name: "전체" }, - { src: images.categoryFreedom, name: "자유" }, - { src: images.categoryDongNea, name: "동네" }, - { src: images.categoryExpert, name: "전문가" }, - { src: images.categoryAnonymity, name: "익명" }, - { src: images.categoryEvent, name: "이벤트" }, + { src: images.categoryAll, name: '전체' }, + { src: images.categoryFreedom, name: '자유' }, + { src: images.categoryDongNea, name: '동네' }, + { src: images.categoryExpert, name: '전문가' }, + { src: images.categoryAnonymity, name: '익명' }, + { src: images.categoryEvent, name: '이벤트' }, ]; - // 게시글 목록 불러오기 useEffect(() => { + // 게시글 목록 불러오기 axios - .get("/communities") - .then((response) => { + .get('/communities') + .then(response => { setCommunityList(response.data); setFilteredCommunityList(response.data); - console.log("게시글 목록:", response.data); - response.data.forEach((item) => { + console.log('게시글 목록:', response.data); + response.data.forEach(item => { if (!userNicknames[item.user]) { fetchUserNickname(item.user); } }); }) - .catch((error) => { - console.error("Error fetching data:", error); + .catch(error => { + console.error('Error fetching data:', error); }); }, []); // 사용자 닉네임 가져오기 함수 - const fetchUserNickname = (userId) => { + const fetchUserNickname = userId => { axios .get(`/user/${userId}`) - .then((response) => { - setUserNicknames((prev) => ({ + .then(response => { + setUserNicknames(prev => ({ ...prev, [userId]: response.data.nickname, })); }) - .catch((error) => { - console.error("Error fetching user nickname:", error); + .catch(error => { + console.error('Error fetching user nickname:', error); }); }; // 좋아요 수 증가 함수 - const good = (postId) => { - const updatedItemList = communityList.map((item) => { + const good = postId => { + const updatedItemList = communityList.map(item => { if (item.postId === postId) { const updatedGood = (item.good || 0) + 1; // 서버의 좋아요 수 업데이트 요청 @@ -67,11 +70,11 @@ const CommunityList = () => { ...item, good: updatedGood, }) - .then((response) => { - console.log("좋아요 업데이트:", response.data); + .then(response => { + console.log('좋아요 업데이트:', response.data); }) - .catch((error) => { - console.error("좋아요 업데이트 실패:", error); + .catch(error => { + console.error('좋아요 업데이트 실패:', error); }); return { ...item, good: updatedGood }; } @@ -85,84 +88,96 @@ const CommunityList = () => { useEffect(() => { axios .get(`/communityComments`) - .then((response) => { + .then(response => { setComments(response.data); - console.log("댓글 목록 :", response.data); + console.log('댓글 목록 :', response.data); }) - .catch((error) => { - console.error("Error fetching data:", error); + .catch(error => { + console.error('Error fetching data:', error); }); }, []); // 카테고리 필터링 함수 - const filterByCategory = (selectedCategory) => { + const filterByCategory = selectedCategory => { setActiveCategory(selectedCategory); - if (selectedCategory === "전체") { + if (selectedCategory === '전체') { setFilteredCommunityList(communityList); } else { - const filteredList = communityList.filter( - (item) => item.category === selectedCategory - ); + const filteredList = communityList.filter(item => item.category === selectedCategory); setFilteredCommunityList(filteredList); } }; + // 검색어로 필터링하는 함수 + const handleSearch = () => { + const filteredList = communityList.filter(item => item.title.toLowerCase().includes(searchQuery.toLowerCase())); + setFilteredCommunityList(filteredList); + }; + + // 검색어가 변경될 때마다 필터링 업데이트 + useEffect(() => { + if (searchQuery === '') { + setFilteredCommunityList(communityList); + } else { + handleSearch(); + } + }, [searchQuery, communityList]); + return ( - - 고양이가 세상을 지배한다 - { - navigate("/community/write"); - }} - > - 글 작성 - - {category.map((item, index) => ( - filterByCategory(item.name)} - > + filterByCategory(item.name)}> {item.name} ))} + + + + setSearchQuery(e.target.value)} + /> + + + { + navigate('/community/write'); + }}> + 글 작성 + + + - {filteredCommunityList.map((item) => ( + {filteredCommunityList.map(item => ( { + onClick={e => { e.preventDefault(); navigate(`/community/detail/${item.postId}`); - }} - > + }}> {item.title} - - 작성자: {userNicknames[item.user] || "로딩 중..."} - + 작성자: {userNicknames[item.user] || '로딩 중...'} - {new Date(item.createdAt).toLocaleDateString("ko-KR", { - timeZone: "Asia/Seoul", + {new Date(item.createdAt).toLocaleDateString('ko-KR', { + timeZone: 'Asia/Seoul', })} { + onClick={e => { e.stopPropagation(); good(item.postId); }} /> {item.good || 0} - { - comments.filter((comment) => comment.post === item.postId) - .length - } + {comments.filter(comment => comment.post === item.postId).length} @@ -178,24 +193,52 @@ export default CommunityList; const ItemTitle = styled.div` height: 100%; width: 100%; - padding: 64px 25px 64px 25px; + padding: 64px 0 80px; display: flex; flex-direction: column; `; const Col = styled.div` width: 100%; + padding: 0 18px; +`; + +const SearchBarWrap = styled.div` display: flex; justify-content: space-between; + margin: 10px 0; + width: 100%; `; -const CommunityText = styled.div` - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; - margin-left: 15px; - font-weight: bold; - color: #ff6e00; + +const SearchInputWrap = styled.div` + position: relative; + width: 200px; `; + +const SearchInput = styled.input` + width: 100%; + padding: 8px 0px 8px 12px; + background-color: #f0f0f0; + border: none; + border-radius: 20px; + font-size: 12px; + outline: none; + transition: border-color 0.3s ease; + + &::placeholder { + color: #888; + font-size: 12px; + } +`; + +const SearchIcon = styled(FaSearch)` + position: absolute; + right: 16px; + top: 50%; + transform: translateY(-50%); + color: #888; + font-size: 10px; +`; + const WriteBtn = styled.button` width: 64px; height: 28px; @@ -209,15 +252,16 @@ const WriteBtn = styled.button` align-items: center; justify-content: center; color: white; - margin-right: 15px; `; const Category = styled.div` width: 100%; height: 83px; - padding: 10px; + margin-bottom: 10px; + padding: 0 20px; display: flex; justify-content: space-between; align-items: center; + background-color: #ffefef; `; const CategoryBtn = styled.div` display: flex; @@ -225,7 +269,7 @@ const CategoryBtn = styled.div` flex-direction: column; align-items: center; cursor: pointer; - opacity: ${({ $active }) => ($active ? "1" : "0.5")}; + opacity: ${({ $active }) => ($active ? '1' : '0.5')}; transition: opacity 0.3s; &:hover { opacity: 1; @@ -238,8 +282,9 @@ const CategoryImg = styled.img` const RowLi = styled.div` display: flex; flex-wrap: wrap; - gap: 16px; - margin: 0 -8px; + margin-top: 10px; + padding: 0 20px; + gap: 20px; `; const Lists = styled.div` width: 100%; @@ -248,12 +293,12 @@ const Lists = styled.div` height: 50px; `; const ListImg = styled.img` - width: 50px; - height: 50px; + width: 60px; + height: 60px; background-color: #d9d9d9; border-radius: 8px; flex-shrink: 0; - background-image: url(${(props) => props.src}); + background-image: url(${props => props.src}); background-size: cover; background-position: center; cursor: pointer; @@ -264,6 +309,7 @@ const ListTitlesContainer = styled.div` flex-direction: column; align-items: center; justify-content: space-between; + margin-left: 5px; padding: 5px; cursor: pointer; `; @@ -287,7 +333,7 @@ const ListDate = styled.div` color: #8d8d8d; width: 100%; align-items: center; - justify-content: flex-end; + justify-content: space-between; `; const Icons = styled.div` display: flex; @@ -300,6 +346,7 @@ const Icons = styled.div` const FcLike1 = styled(FcLike)` font-size: 16px; cursor: pointer; + margin-bottom: 1px; `; const Comment1 = styled(IoChatbubbleEllipsesOutline)` font-size: 16px; diff --git a/src/pages/LoginPage/LoginPage.jsx b/src/pages/LoginPage/LoginPage.jsx index 7815d3c..a98d348 100644 --- a/src/pages/LoginPage/LoginPage.jsx +++ b/src/pages/LoginPage/LoginPage.jsx @@ -1,7 +1,7 @@ -import styled from "styled-components"; -import { images } from "../../components/Images"; -import { useNavigate } from "react-router-dom"; -import loginbtn from "./loginbtn.png"; +import styled from 'styled-components'; +import { images } from '../../components/Images'; +import { useNavigate } from 'react-router-dom'; +import loginbtn from './loginbtn.png'; const LoginPage = () => { const navigate = useNavigate(); @@ -9,13 +9,15 @@ const LoginPage = () => { return ( 로그인 화면 강아지와 고양이 그림 - 지금 가입하면 5천원 즉시 할인! + + 지금 가입하면 <StyledTitle>5천원 즉시 할인!</StyledTitle>{' '} + 우리 댕냥이 엄마쇼핑 시작해볼까요? 카카오 계정으로 로그인 다른 방법으로 시작하기 - navigate("/")}>일단 둘러보기 + navigate('/')}>일단 둘러보기 ); }; @@ -47,6 +49,10 @@ const Title = styled.h2` text-align: center; `; +const StyledTitle = styled.span` + color: #ff6e00; +`; + const Subtitle = styled.p` font-size: 14px; color: #666666; @@ -67,12 +73,15 @@ const Button = styled.button` `; const OtherMethodButton = styled(Button)` - background-color: #f5f5f5; - color: #666666; + background-color: #f0f0f0; + color: #b3b3b3; + border-radius: 8px; + margin-top: 5px; + font-size: 14px; &:hover { - background-color: #e0e0e0; - transform: scale(1.05); + background-color: #ff6e00; + color: #ffffff; } `; diff --git a/src/pages/MainPage/MainPage.jsx b/src/pages/MainPage/MainPage.jsx index 04174a8..af9d833 100644 --- a/src/pages/MainPage/MainPage.jsx +++ b/src/pages/MainPage/MainPage.jsx @@ -106,84 +106,88 @@ const MainPage = () => { return ( <> - - - - - - - - - 사랑하는 우리응애용품 한 곳에서 해결하세요! - - - - setSearchQuery(e.target.value)} + + + + + - - - - - - {tabs.map(tab => ( - setActiveTab(tab)}> - {tab} - - ))} - - - {categories.map(category => ( - setActiveCategory(category)}> - {category} - - ))} - - - - {paginatedData.map(product => ( - - - - {product.productTitle.replace(/<[^>]*>/g, '')} - {Number(product.productLprice).toLocaleString()}원 - - - ))} - - - - - - - {pageRange.map(p => ( - handlePageChange(p)} $active={page === p}> - {p} + + + + + 사랑하는 우리응애용품 한 곳에서 해결하세요! + + + + setSearchQuery(e.target.value)} + /> + + + + + + {tabs.map(tab => ( + setActiveTab(tab)}> + {tab} + + ))} + + + {categories.map(category => ( + setActiveCategory(category)}> + {category} + + ))} + + + + {paginatedData.map(product => ( + + + + {product.productTitle.replace(/<[^>]*>/g, '')} + {Number(product.productLprice).toLocaleString()}원 + + + ))} + + + + + - ))} - = Math.ceil(data.length / itemsPerPage)}> - - - + {pageRange.map(p => ( + handlePageChange(p)} $active={page === p}> + {p} + + ))} + = Math.ceil(data.length / itemsPerPage)}> + + + + ); }; export default MainPage; +const Container = styled.div` + padding: 64px 0 0; +`; const CarouselContainer = styled.div` position: relative; width: 100%; height: 140px; - margin-top: 64px; display: flex; align-items: center; justify-content: center; @@ -376,4 +380,4 @@ const PageButton = styled.button` &:hover { color: #ff6e00; } -`; \ No newline at end of file +`; diff --git a/src/pages/NanumPage/NanumList.jsx b/src/pages/NanumPage/NanumList.jsx index 099dbb6..0b5a304 100644 --- a/src/pages/NanumPage/NanumList.jsx +++ b/src/pages/NanumPage/NanumList.jsx @@ -1,11 +1,11 @@ -import { useEffect, useState } from "react"; -import { useNavigate } from "react-router-dom"; -import styled from "styled-components"; -import { LuSearch } from "react-icons/lu"; -import { IoChatbubbleEllipsesOutline } from "react-icons/io5"; -import { FcLike } from "react-icons/fc"; -import axios from "../../apis/AxiosInstance"; -import { HiArrowSmDown } from "react-icons/hi"; +import { useEffect, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import styled from 'styled-components'; +import { LuSearch } from 'react-icons/lu'; +import { IoChatbubbleEllipsesOutline } from 'react-icons/io5'; +import { FcLike } from 'react-icons/fc'; +import axios from '../../apis/AxiosInstance'; +import { HiArrowSmDown } from 'react-icons/hi'; const PetItemListPage = () => { const navigate = useNavigate(); @@ -17,40 +17,40 @@ const PetItemListPage = () => { //게시글 목록 불러오기 useEffect(() => { axios - .get("/petItems") - .then((response) => { + .get('/petItems') + .then(response => { setPetItemList(response.data); // 응답 데이터 저장 - console.log("게시글 목록:", response.data); + console.log('게시글 목록:', response.data); // 각 사용자 닉네임을 가져오는 함수 호출 - response.data.forEach((item) => { + response.data.forEach(item => { if (!userNicknames[item.user]) { fetchUserNickname(item.user); } }); }) - .catch((error) => { - console.error("Error fetching data:", error); + .catch(error => { + console.error('Error fetching data:', error); }); }, []); // 사용자 닉네임 가져오기 함수 - const fetchUserNickname = (userId) => { + const fetchUserNickname = userId => { axios .get(`/user/${userId}`) - .then((response) => { - setUserNicknames((prev) => ({ + .then(response => { + setUserNicknames(prev => ({ ...prev, [userId]: response.data.nickname, })); }) - .catch((error) => { - console.error("Error fetching user nickname:", error); + .catch(error => { + console.error('Error fetching user nickname:', error); }); }; // 좋아요 수 증가 함수 - const good = (petItemId) => { - const updatedItemList = petItemList.map((item) => { + const good = petItemId => { + const updatedItemList = petItemList.map(item => { if (item.petItemId === petItemId) { const updatedGood = (item.good || 0) + 1; // 서버의 좋아요 수 업데이트 요청 @@ -59,11 +59,11 @@ const PetItemListPage = () => { ...item, good: updatedGood, }) - .then((response) => { - console.log("좋아요 업데이트:", response.data); + .then(response => { + console.log('좋아요 업데이트:', response.data); }) - .catch((error) => { - console.error("좋아요 업데이트 실패:", error); + .catch(error => { + console.error('좋아요 업데이트 실패:', error); }); return { ...item, good: updatedGood }; } @@ -76,20 +76,18 @@ const PetItemListPage = () => { useEffect(() => { axios .get(`/petItemComments`) - .then((response) => { + .then(response => { setComments(response.data); - console.log("댓글 목록 :", response.data); + console.log('댓글 목록 :', response.data); }) - .catch((error) => { - console.error("Error fetching data:", error); + .catch(error => { + console.error('Error fetching data:', error); }); }, []); // 최신순 const handleLatest = () => { - const sortList = [...petItemList].sort( - (a, b) => new Date(b.createdAt) - new Date(a.createdAt) - ); + const sortList = [...petItemList].sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)); setPetItemList(sortList); setLatest(true); //정렬 변경 }; @@ -106,9 +104,8 @@ const PetItemListPage = () => { { - navigate("/nanumList/write"); - }} - > + navigate('/nanumList/write'); + }}> 글 작성 @@ -116,45 +113,32 @@ const PetItemListPage = () => { 전체 {petItemList.length.toLocaleString()}개 - {petItemList.map((item) => ( + {petItemList.map(item => ( { + onClick={e => { e.preventDefault(); navigate(`/nanumList/detail/${item.petItemId}`); - }} - > + }}> {item.name} - - 작성자: {userNicknames[item.user] || "로딩 중..."} - - - {item.price ? ( - `${item.price.toLocaleString()}원` - ) : ( - <나눔>나눔 - )} - + 작성자: {userNicknames[item.user] || '로딩 중...'} + {item.price ? `${item.price.toLocaleString()}원` : <나눔>나눔} - {new Date(item.createdAt).toLocaleDateString("ko-KR", { - timeZone: "Asia/Seoul", + {new Date(item.createdAt).toLocaleDateString('ko-KR', { + timeZone: 'Asia/Seoul', })} { + onClick={e => { e.stopPropagation(); good(item.petItemId); }} /> {item.good || 0} - { - comments.filter( - (comment) => comment.petItem === item.petItemId - ).length - } + {comments.filter(comment => comment.petItem === item.petItemId).length} @@ -170,7 +154,7 @@ export default PetItemListPage; const ItemTitle = styled.div` height: 100%; width: 100%; - padding: 64px 25px 64px 25px; + padding: 64px 25px 80px 25px; display: flex; flex-direction: column; `; @@ -262,7 +246,7 @@ const ListImg = styled.img` background-color: #d9d9d9; border-radius: 8px; flex-shrink: 0; /* 이미지 크기를 고정 */ - background-image: url(${(props) => props.src}); + background-image: url(${props => props.src}); background-size: cover; background-position: center; cursor: pointer; @@ -274,6 +258,7 @@ const ListTitlesContainer = styled.div` align-items: center; justify-content: space-between; /* 상하 간격 자동 배분 */ padding: 5px; + margin-left: 8px; cursor: pointer; `; const ListTItle = styled.div` @@ -311,7 +296,7 @@ const ListDate = styled.div` color: #8d8d8d; width: 100%; align-items: center; - justify-content: flex-end; + justify-content: space-between; `; const Icons = styled.div` display: flex; diff --git a/src/pages/NanumPage/NanumWrite.jsx b/src/pages/NanumPage/NanumWrite.jsx index f8f6ccb..4dc0e36 100644 --- a/src/pages/NanumPage/NanumWrite.jsx +++ b/src/pages/NanumPage/NanumWrite.jsx @@ -1,63 +1,59 @@ -import styled from "styled-components"; -import { MdPhotoCamera } from "react-icons/md"; -import axios from "../../apis/AxiosInstance"; -import { useEffect, useState } from "react"; -import { useNavigate } from "react-router-dom"; +import styled from 'styled-components'; +import { MdPhotoCamera } from 'react-icons/md'; +import axios from '../../apis/AxiosInstance'; +import { useEffect, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; const PetItemPage = () => { - const [selectedSaleType, setSelectedSaleType] = useState(""); // 버튼 판매 or 나눔 + const [selectedSaleType, setSelectedSaleType] = useState(''); // 버튼 판매 or 나눔 const [showPriceBox, setShowPriceBox] = useState(false); // 가격 입력 박스 표시 여부 - const [uploadedImage, setUploadedImage] = useState(""); //미리보기 이미지 - const [name, setName] = useState(""); // 제목 - const [description, setDescription] = useState(""); // 내용 - const [price, setPrice] = useState(""); // 판매가격 - const [user, setUser] = useState(""); // 유저 + const [uploadedImage, setUploadedImage] = useState(''); //미리보기 이미지 + const [name, setName] = useState(''); // 제목 + const [description, setDescription] = useState(''); // 내용 + const [price, setPrice] = useState(''); // 판매가격 + const [user, setUser] = useState(''); // 유저 const [imageUrl, setImageUrl] = useState(null); // 사진 파일 - const [sharing, setSharing] = useState(""); // 나눔 . 판매 여부 + const [sharing, setSharing] = useState(''); // 나눔 . 판매 여부 const [loading, setLoading] = useState(false); const navigate = useNavigate(); - const handleSubmit = async (e) => { - const user = localStorage.getItem("userId"); + const handleSubmit = async e => { + const user = localStorage.getItem('userId'); e.preventDefault(); // 새로고침 방지 setLoading(true); const formData = new FormData(); - formData.append("name", name); - formData.append("description", description); - formData.append("price", price); - formData.append("user", user); - formData.append("sharing", sharing); + formData.append('name', name); + formData.append('description', description); + formData.append('price', price); + formData.append('user', user); + formData.append('sharing', sharing); if (imageUrl) { - formData.append("imageUrl", imageUrl); + formData.append('imageUrl', imageUrl); } try { - const response = await axios.post( - "https://ureca.store/api/petItems", - formData, - { - headers: { - "Content-Type": "multipart/form-data", - }, - } - ); - console.log("등록 data : ", response.data); - navigate("/nanumList"); - setName(""); - setDescription(""); - setPrice(""); - setUser(""); - setSharing(""); + const response = await axios.post('https://ureca.store/api/petItems', formData, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }); + console.log('등록 data : ', response.data); + navigate('/nanumList'); + setName(''); + setDescription(''); + setPrice(''); + setUser(''); + setSharing(''); setImageUrl(null); // 이미지 URL 초기화 setUploadedImage(null); // 미리보기 이미지 초기화 } catch (error) { - console.error("오류 발생:", error); - alert("오류 발생:"); - setName(""); - setDescription(""); - setPrice(""); - setUser(""); - setSharing(""); + console.error('오류 발생:', error); + alert('오류 발생:'); + setName(''); + setDescription(''); + setPrice(''); + setUser(''); + setSharing(''); setImageUrl(null); // 이미지 URL 초기화 setUploadedImage(null); // 미리보기 이미지 초기화 } finally { @@ -66,37 +62,32 @@ const PetItemPage = () => { }; // }, []); // 파일 선택 핸들러 - const handleFileChange = (e) => { + const handleFileChange = e => { if (e.target.files && e.target.files[0]) { const file = e.target.files[0]; // 첫 번째 파일만 선택 setImageUrl(file); setUploadedImage(URL.createObjectURL(file)); if (file.length > 1) { - alert("최대 1장의 이미지만 선택할 수 있습니다."); + alert('최대 1장의 이미지만 선택할 수 있습니다.'); return; } } }; - const handleSaleTypeClick = (type) => { + const handleSaleTypeClick = type => { setSelectedSaleType(type); - setSharing(type === "판매" ? 1 : 0); - setShowPriceBox(type === "판매"); // '판매' 선택 시만 가격 입력 박스 표시 - setPrice(type === "판매" ? "" : "0"); + setSharing(type === '판매' ? 1 : 0); + setShowPriceBox(type === '판매'); // '판매' 선택 시만 가격 입력 박스 표시 + setPrice(type === '판매' ? '' : '0'); }; return (
+ 사진 첨부 - + {uploadedImage ? ( { id="name" value={name} type="text" - onChange={(e) => setName(e.target.value)} + onChange={e => setName(e.target.value)} required - placeholder="제목을 입력해주세요" + placeholder="제목을 입력해주세요." /> 거래 방식 handleSaleTypeClick("판매")} - selected={selectedSaleType === "판매"} - onChange={() => handleSaleTypeClick("판매")} - > - 판매하기 + onClick={() => handleSaleTypeClick('판매')} + selected={selectedSaleType === '판매'} + onChange={() => handleSaleTypeClick('판매')}> + 판매 - handleSaleTypeClick("나눔")} - selected={selectedSaleType === "나눔"} - > - 나눔하기 + handleSaleTypeClick('나눔')} selected={selectedSaleType === '나눔'}> + 나눔 {showPriceBox && ( @@ -143,7 +130,7 @@ const PetItemPage = () => { value={price} id="price" type="number" - onChange={(e) => setPrice(e.target.value)} + onChange={e => setPrice(e.target.value)} placeholder="금액을 입력해주세요" />
@@ -153,7 +140,7 @@ const PetItemPage = () => {