From 9790c5a2145b2f763d7fbe6ecd463fb3ddbf66e6 Mon Sep 17 00:00:00 2001 From: StarrySnowy Date: Thu, 7 Nov 2024 13:21:07 +0100 Subject: [PATCH 01/12] feature: search --- client/src/components/search/search.css | 75 +++---------------------- client/src/components/search/search.js | 1 + client/src/pages/CheongtakjuPage.js | 3 +- client/src/pages/FruitWinePage.js | 3 +- 4 files changed, 14 insertions(+), 68 deletions(-) diff --git a/client/src/components/search/search.css b/client/src/components/search/search.css index c00f0d5..663e727 100644 --- a/client/src/components/search/search.css +++ b/client/src/components/search/search.css @@ -1,67 +1,10 @@ -/* searchpage.css */ - /* 페이지 전체 레이아웃 */ -.search-container { - display: flex; - flex-direction: column; - align-items: center; - padding: 20px; - max-width: 600px; - margin: 0 auto; - } - - /* 검색창 스타일 */ - .search-input { - width: 100%; - padding: 10px; - font-size: 16px; - border: 1px solid #ddd; - border-radius: 5px; - margin-bottom: 15px; - } - - /* 검색 버튼 스타일 */ - .search-button { - padding: 10px 20px; - font-size: 16px; - background-color: #4CAF50; - color: white; - border: none; - border-radius: 5px; - cursor: pointer; - margin-bottom: 20px; - transition: background-color 0.3s ease; - } - - .search-button:hover { - background-color: #45a049; - } - - /* 결과 리스트 스타일 */ - .results-list { - list-style: none; - padding: 0; - width: 100%; - } - - .result-item { - padding: 15px; - margin-bottom: 10px; - border: 1px solid #ddd; - border-radius: 5px; - background-color: #f9f9f9; - font-size: 18px; - } - - /* 텍스트 정렬 */ - .result-item h3 { - margin: 0; - font-size: 20px; - color: #333; - } - - .result-item p { - margin: 5px 0 0; - color: #666; - } - \ No newline at end of file +input { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; /* 수직 중앙 정렬 */ + padding: 20px; + max-width: 600px; + margin: 10%; +} diff --git a/client/src/components/search/search.js b/client/src/components/search/search.js index 8561a04..39e40d2 100644 --- a/client/src/components/search/search.js +++ b/client/src/components/search/search.js @@ -1,5 +1,6 @@ import React, { useState, useEffect } from "react"; import axios from "axios"; +import "./search.css"; function SearchPage() { const [searchQuery, setSearchQuery] = useState(""); diff --git a/client/src/pages/CheongtakjuPage.js b/client/src/pages/CheongtakjuPage.js index 4f52eff..0eb2118 100644 --- a/client/src/pages/CheongtakjuPage.js +++ b/client/src/pages/CheongtakjuPage.js @@ -3,12 +3,13 @@ import AlcoholList from "../components/alcoholList/AlcoholList"; import SearchBar from "../components/navSearchBar/SearchBar"; import Footer from "../components/common/Footer"; import cheongTakjuListApi from "../api/cheongTakjuListApi"; +import SearchPage from "../components/search/search"; const CheongtakjuPage = () => { return (
- +
diff --git a/client/src/pages/FruitWinePage.js b/client/src/pages/FruitWinePage.js index 4289129..f5d1ce5 100644 --- a/client/src/pages/FruitWinePage.js +++ b/client/src/pages/FruitWinePage.js @@ -3,12 +3,13 @@ import SearchBar from "../components/navSearchBar/SearchBar"; import AlcoholList from "../components/alcoholList/AlcoholList"; import fruitWineListApi from "../api/fruitWineListApi"; import Footer from "../components/common/Footer"; +import SearchPage from "../components/search/search"; const FruitWinePage = () => { return (
- +
From 0c69281f2b97322731b4113aa4f06b158e2cab55 Mon Sep 17 00:00:00 2001 From: StarrySnowy Date: Wed, 13 Nov 2024 08:42:18 +0100 Subject: [PATCH 02/12] feature: mypage, searchbar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 닉네임 편집시 텍스트 자동삭제 닉네임 제한 마이페이지 담은 술 '추가 버튼' 기능 수정 --- client/public/data/drinks.json | 705 ++++++++++++++++++++++++ client/src/components/search/search.css | 29 +- client/src/components/search/search.js | 26 +- client/src/pages/FruitWinePage.js | 2 +- client/src/pages/mypage.css | 20 +- client/src/pages/mypage.js | 45 +- 6 files changed, 807 insertions(+), 20 deletions(-) create mode 100644 client/public/data/drinks.json diff --git a/client/public/data/drinks.json b/client/public/data/drinks.json new file mode 100644 index 0000000..bde43ee --- /dev/null +++ b/client/public/data/drinks.json @@ -0,0 +1,705 @@ +[ +{ + "drinkName": "치키피치", + "preferenceLevel":4.6, + "area": "충청북도", + "type": "과실주", + "postImage": "/images/fruitWine/CheekyPeach.jpg" +},{ + "drinkName": "P.S 화이트 스파클링", + "preferenceLevel":5, + "area": "충청북도", + "type": "과실주", + "postImage": "/images/fruitWine/PS_WhiteSparkling.jpg" +},{ + "drinkName": "멜론서리", + "preferenceLevel":5, + "area": "충청북도", + "type": "과실주", + "postImage": "/images/fruitWine/MellonSeoli.jpg" +},{ + "drinkName": "오롯이 복숭아", + "preferenceLevel":9, + "area": "세종특별자치시", + "type": "과실주", + "postImage": "/images/fruitWine/OlosiPeache.jpg" +},{ + "drinkName": "너브내스파클링사과와인", + "preferenceLevel":8.5, + "area": "강원도", + "type": "과실주", + "postImage": "/images/fruitWine/NervneSparklingAppleWine.jpg" +},{ + "drinkName": "로제사이더 오미한잔", + "preferenceLevel":4.5, + "area": "경상북도", + "type": "과실주", + "postImage": "/images/fruitWine/RoseCiderOmihanjan.jpg" +},{ + "drinkName": "세인트하우스 살구와인", + "preferenceLevel":12, + "area": "충청남도 ", + "type": "과실주", + "postImage": "/images/fruitWine/SaintHouseApricotWine.jpg" +},{ + "drinkName": "머루와인", + "preferenceLevel":12, + "area": "전라북도", + "type": "과실주", + "postImage": "/images/fruitWine/MeruWine.jpg" +},{ + "drinkName": "그랑꼬또 청수", + "preferenceLevel":12, + "area": "경기도", + "type": "과실주", + "postImage": "/images/fruitWine/GradcoteauFreshWater.jpg" +},{ + "drinkName": "베베마루 설레임 로제 스위트와인", + "preferenceLevel":12, + "area": "충청북도", + "type": "과실주", + "postImage": "/images/fruitWine/RoséSweetWine.jpg" +},{ + "drinkName": "산막와이너리, 화몽", + "preferenceLevel":13, + "area": "충청북도", + "type": "과실주", + "postImage": "/images/fruitWine/Hwamong.jpg" +},{ + "drinkName": "산막와이너리, 비원퓨어", + "preferenceLevel":13, + "area": "충청북도", + "type": "과실주", + "postImage": "/images/fruitWine/BiwonPure.jpg" +},{ + "drinkName": "크라테 화이트스위트", + "preferenceLevel":11.5, + "area": "경상북도", + "type": "과실주", + "postImage": "/images/fruitWine/KratteWhiteSweet.jpg" +},{ + "drinkName": "김천대학교 자두사랑 자두와인", + "preferenceLevel":12, + "area": "경상북도", + "type": "과실주", + "postImage": "/images/fruitWine/GimcheonUniversityPlumWine.jpg" +},{ + "drinkName": "미르아토 로제와인", + "preferenceLevel":12, + "area": "충청북도", + "type": "과실주", + "postImage": "/images/fruitWine/MiratoRoseWine.jpg" +},{ + "drinkName": "산머루와인 달콤한 스위트", + "preferenceLevel":10.5, + "area": "경상남도", + "type": "과실주", + "postImage": "/images/fruitWine/SweetSweet.jpg" +},{ + "drinkName": "2016년산 하미앙 드라이", + "preferenceLevel":12, + "area": "경상남도", + "type": "과실주", + "postImage": "/images/fruitWine/HamianDry.jpg" +},{ + "drinkName": "고도리 로제와인", + "preferenceLevel":12, + "area": "경상북도", + "type": "과실주", + "postImage": "/images/fruitWine/GodoriRoseWine.jpg" +},{ + "drinkName": "소계리 595 스위트 레드와인", + "preferenceLevel":12, + "area": "충청북도", + "type": "과실주", + "postImage": "/images/fruitWine/559SweetRedWine.jpg" +},{ + "drinkName": "끌로너와 스위트와인", + "preferenceLevel":12, + "area": "강원도", + "type": "과실주", + "postImage": "/images/fruitWine/ClonerAndSweetWine.jpg" +},{ + "drinkName": "고도리 샤인머스캣 화이트와인", + "preferenceLevel":10.5, + "area": "경상북도", + "type": "과실주", + "postImage": "/images/fruitWine/ShineMuscatWhiteWine.jpg" +},{ + "drinkName": "포엠 화이트와인", + "preferenceLevel":12, + "area": "충청북도", + "type": "과실주", + "postImage": "/images/fruitWine/PoemWhiteWine.jpg" +},{ + "drinkName": "산막와이너리, 초련", + "preferenceLevel":20, + "area": "충청북도", + "type": "과실주", + "postImage": "/images/fruitWine/Choryun.jpg" +},{ + "drinkName": "코이버펑크, 머스캣 베일리 에이 2017", + "preferenceLevel":12.5, + "area": "경상북도", + "type": "과실주", + "postImage": "/images/fruitWine/MuscatBaileyA.jpg" +},{ + "drinkName": "산막와이너리, 아로퓨어", + "preferenceLevel":13, + "area": "충청북도 ", + "type": "과실주", + "postImage": "/images/fruitWine/Aropure.jpg" +},{ + "drinkName": "뱅꼬레 더감", + "preferenceLevel":12, + "area": "경상북도", + "type": "과실주", + "postImage": "/images/fruitWine/BancoreDeogam.jpg" +},{ + "drinkName": "샤토미소 아이스와인", + "preferenceLevel":12, + "area": "충청북도", + "type": "과실주", + "postImage": "/images/fruitWine/SyatomisoIceWine.jpg" +},{ + "drinkName": "산머루와인 깊은맛 드라이", + "preferenceLevel":12, + "area": "경라남도", + "type": "과실주", + "postImage": "/images/fruitWine/MeruWineDeepDry.jpg" +},{ + "drinkName": "너브내 로제 스파클링", + "preferenceLevel":12, + "area": "강원도", + "type": "과실주", + "postImage": "/images/fruitWine/NeubnaeRoséSparkling.jpg" +},{ + "drinkName": "달 1614 스위트와인", + "preferenceLevel":12, + "area": "전라북도", + "type": "과실주", + "postImage": "/images/fruitWine/Moon1614SweetWine.jpg" +},{ + "drinkName": "샤토미소 웨딩 자두와인", + "preferenceLevel":12, + "area": "충청북도", + "type": "과실주", + "postImage": "/images/fruitWine/WeddingPlumWine.jpg" +},{ + "drinkName": "코이버펑크, 카베르네 소비뇽 2019", + "preferenceLevel":12.5, + "area": "경상북도", + "type": "과실주", + "postImage": "/images/fruitWine/CabernetSauvignon.jpg" +},{ + "drinkName": "포엠 로제와인", + "preferenceLevel":12, + "area": "충청북도", + "type": "과실주", + "postImage": "/images/fruitWine/PoemRoséWine.jpg" +},{ + "drinkName": "2016년산 하미앙 스위트", + "preferenceLevel":10.5, + "area": "경라남도", + "type": "과실주", + "postImage": "/images/fruitWine/HamiangSweet.jpg" +},{ + "drinkName": "베리와인1168 스위트와인", + "preferenceLevel":13, + "area": "충청북도", + "type": "과실주", + "postImage": "/images/fruitWine/1168SweetWine.jpg" +},{ + "drinkName": "오크와인", + "preferenceLevel":12, + "area": "경라남도", + "type": "과실주", + "postImage": "/images/fruitWine/OakWine.jpg" +},{ + "drinkName": "너브내 스파클링 화이트", + "preferenceLevel":12, + "area": "강원도", + "type": "과실주", + "postImage": "/images/fruitWine/SparklingWhite.jpg" +},{ + "drinkName": "소백산(샤토소백) 스위트 레드와인", + "preferenceLevel":12, + "area": "경상북도", + "type": "과실주", + "postImage": "/images/fruitWine/SobakSweetRedWine.jpg" +},{ + "drinkName": "크라테 미디엄드라이", + "preferenceLevel":11.5, + "area": "경상북도", + "type": "과실주", + "postImage": "/images/fruitWine/MediumDry.jpg" +},{ + "drinkName": "2018년산 하미앙 오크와인", + "preferenceLevel":12, + "area": "경라남도", + "type": "과실주", + "postImage": "/images/fruitWine/HamianOakWine.jpg" +}, + + {"drinkName":"소풍", + "preferenceLevel":5.5, + "area":"경상남도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju1.jpg" + }, + + {"drinkName":"가와지탁주", + "preferenceLevel":7.5, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju2.jpg" + }, + + {"drinkName":"연희유자", + "preferenceLevel":10, + "area":"서울특별시", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju3.jpg" + }, + + {"drinkName":"팔팔막걸리", + "preferenceLevel":6, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju4.jpg" + }, + + {"drinkName":"설레 7도", + "preferenceLevel":7, + "area":"경상남도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju5.jpg" + }, + + {"drinkName":"보은주", + "preferenceLevel":10, + "area":"충청북도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju6.jpg" + }, + + {"drinkName":"바텐더의막걸리", + "preferenceLevel":14, + "area":"서울특별시", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju7.jpg" + }, + + {"drinkName":"김유정역", + "preferenceLevel":6, + "area":"강원도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju8.jpg" + }, + + {"drinkName":"님 그리다", + "preferenceLevel":6, + "area":"경상남도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju9.jpg" + }, + + {"drinkName":"일엽편주", + "preferenceLevel":12, + "area":"경상북도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju10.jpg" + }, + + {"drinkName":"입장탁주", + "preferenceLevel":7, + "area":"충청남도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju11.jpg" + }, + + {"drinkName":"메들리손막걸리", + "preferenceLevel":8, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju12.jpg" + }, + + {"drinkName":"자작막걸리", + "preferenceLevel":12, + "area":"강원도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju13.jpg" + }, + + {"drinkName":"냥이탁주 화이트", + "preferenceLevel":10.5, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju14.jpg" + }, + + {"drinkName":"대대포9", + "preferenceLevel":9, + "area":"전라남도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju15.jpg" + }, + + {"drinkName":"아임프리6.0", + "preferenceLevel":6, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju16.jpg" + }, + + {"drinkName":"냥이탁주 9도", + "preferenceLevel":9, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju17.jpg" + }, + + {"drinkName":"골목막걸리 프리미엄 12", + "preferenceLevel":12, + "area":"충청남도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju18.jpg" + }, + + {"drinkName":"과천미주", + "preferenceLevel":9, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju19.jpg" + }, + + {"drinkName":"복순도가 슈퍼드라이", + "preferenceLevel":6.5, + "area":"울산광역시", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju20.jpg" + }, + + {"drinkName":"옹근달 본막걸리", + "preferenceLevel":15, + "area":"인천광역시", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju21.jpg" + }, + + {"drinkName":"산정호수 동정춘막걸리", + "preferenceLevel":6, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju22.jpg" + }, + + {"drinkName":"단홍", + "preferenceLevel":13.5, + "area":"서울특별시", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju23.jpg" + }, + + {"drinkName":"오산막걸리", + "preferenceLevel":6, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju24.jpg" + }, + + {"drinkName":"일곱쌀", + "preferenceLevel":7, + "area":"서울특별시", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju25.jpg" + }, + + {"drinkName":"탁112클래식", + "preferenceLevel":12, + "area":"인천광역시", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju26.jpg" + }, + + {"drinkName":"생 옥수수 동동주", + "preferenceLevel":6, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju27.jpg" + }, + + {"drinkName":"담향 대대포 블루", + "preferenceLevel":6, + "area":"전라남도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju28.jpg" + }, + + {"drinkName":"도갓집 막걸리", + "preferenceLevel":6, + "area":"전라남도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju29.jpg" + }, + + {"drinkName":"한영석 하향주", + "preferenceLevel":13.8, + "area":"전라북도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju30.jpg" + }, + + {"drinkName":"이화주(술샘)", + "preferenceLevel":8, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju31.jpg" + }, + + {"drinkName":"관악산생막걸리", + "preferenceLevel":6, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju32.jpg" + }, + + {"drinkName":"하얀까마귀", + "preferenceLevel":8, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju33.jpg" + }, + + {"drinkName":"정감생막걸리", + "preferenceLevel":6, + "area":"경상남도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju34.jpg" + }, + + {"drinkName":"눈내린여름밤", + "preferenceLevel":12, + "area":"서울특별시", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju35.jpg" + }, + + {"drinkName":"한강의설레임", + "preferenceLevel":11, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju36.jpg" + }, + + {"drinkName":"시향가 미니캔막걸리", + "preferenceLevel":8, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju37.jpg" + }, + + {"drinkName":"강냉이 막걸리", + "preferenceLevel":6, + "area":"충청북도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju38.jpg" + }, + + {"drinkName":"말이야 막걸리야", + "preferenceLevel":6, + "area":"전라남도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju39.jpg" + }, + + {"drinkName":"연꽃담은술", + "preferenceLevel":8, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju40.jpg" + }, + + {"drinkName":"냥이탁주 fresh", + "preferenceLevel":5, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju41.jpg" + }, + + {"drinkName":"주홍춘", + "preferenceLevel":10, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju42.jpg" + }, + + {"drinkName":"양조학당 뜰", + "preferenceLevel":12, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju43.jpg" + }, + + {"drinkName":"금풍양조", + "preferenceLevel":6.9, + "area":"인천광역시", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju44.jpg" + }, + + {"drinkName":"영일만친구 막걸리", + "preferenceLevel":6, + "area":"경상북도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju45.jpg" + }, + + {"drinkName":"선희주", + "preferenceLevel":12, + "area":"충청북도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju46.jpg" + }, + + {"drinkName":"연오랑탁주", + "preferenceLevel":12, + "area":"경상북도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju47.jpg" + }, + + {"drinkName":"청혼 화이트", + "preferenceLevel":13, + "area":"경기도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju48.jpg" + }, + + {"drinkName":"오희 스파클링 막걸리", + "preferenceLevel":8.5, + "area":"경상북도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju49.jpg" + }, + + {"drinkName":"곤드레생막걸리", + "preferenceLevel":6, + "area":"강원도", + "type":"탁주", + "postIamge":"/images/cheongtakju/takju50.jpg" + }, + + {"drinkName":"세종대왕어주 약주", + "preferenceLevel":15, + "area":"충청북도", + "type":"청주", + "postIamge":"/images/cheongtakju/cheongju1.jpg" + }, + + {"drinkName":"주교주", + "preferenceLevel":16, + "area":"경기도", + "type":"청주", + "postIamge":"/images/cheongtakju/cheongju2.jpg" + }, + + {"drinkName":"일엽편주", + "preferenceLevel":15, + "area":"경상북도", + "type":"청주", + "postIamge":"/images/cheongtakju/cheongju3.jpg" + }, + + {"drinkName":"모월 연", + "preferenceLevel":13, + "area":"강원도", + "type":"청주", + "postIamge":"/images/cheongtakju/cheongju4.jpg" + }, + + {"drinkName":"메들리아카시아", + "preferenceLevel":7, + "area":"경기도", + "type":"청주", + "postIamge":"/images/cheongtakju/cheongju5.jpg" + }, + + {"drinkName":"경산대추약주 추", + "preferenceLevel":16, + "area":"경상북도", + "type":"청주", + "postIamge":"/images/cheongtakju/cheongju6.jpg" + }, + + {"drinkName":"보리수헤는밤", + "preferenceLevel":8, + "area":"충청남도", + "type":"청주", + "postIamge":"/images/cheongtakju/cheongju7.jpg" + }, + + {"drinkName":"지란지교 약주", + "preferenceLevel":17, + "area":"전라북도", + "type":"청주", + "postIamge":"/images/cheongtakju/cheongju8.jpg" + }, + + {"drinkName":"모월 청", + "preferenceLevel":16, + "area":"강원도", + "type":"청주", + "postIamge":"/images/cheongtakju/cheongju9.jpg" + }, + + {"drinkName":"담골드", + "preferenceLevel":12, + "area":"경기도", + "type":"청주", + "postIamge":"/images/cheongtakju/cheongju10.jpg" + }, + + {"drinkName":"청혼 블루", + "preferenceLevel":15, + "area":"경기도", + "type":"청주", + "postIamge":"/images/cheongtakju/cheongju11.jpg" + }, + + {"drinkName":"복단지", + "preferenceLevel":14, + "area":"경기도", + "type":"청주", + "postIamge":"/images/cheongtakju/cheongju12.jpg" + }, + + {"drinkName":"서설", + "preferenceLevel":13, + "area":"경기도", + "type":"청주", + "postIamge":"/images/cheongtakju/cheongju13.jpg" + }, + + {"drinkName":"호산춘", + "preferenceLevel":18, + "area":"경상북도", + "type":"청주", + "postIamge":"/images/cheongtakju/cheongju14.jpg" + }, + + {"drinkName":"일지춘", + "preferenceLevel":15, + "area":"강원도", + "type":"청주", + "postIamge":"/images/cheongtakju/cheongju15.jpg" + }, + + {"drinkName":"과하주 온", + "preferenceLevel":18.5, + "area":"강원도", + "type":"청주", + "postIamge":"/images/cheongtakju/cheongju16.jpg" + } +] \ No newline at end of file diff --git a/client/src/components/search/search.css b/client/src/components/search/search.css index 663e727..2552c58 100644 --- a/client/src/components/search/search.css +++ b/client/src/components/search/search.css @@ -1,10 +1,29 @@ /* 페이지 전체 레이아웃 */ -input { +.search-container { display: flex; - flex-direction: column; align-items: center; - justify-content: center; /* 수직 중앙 정렬 */ - padding: 20px; + justify-content: center; /* 수평 중앙 정렬 */ + background-color: #d6d1c9; + border-radius: 20px; + padding: 10px 15px; max-width: 600px; - margin: 10%; + margin-top: 90px; + margin-left: auto; + margin-right: auto; /* 좌우 중앙 정렬 */ +} + +.search-input { + flex: 1; + border: none; + outline: none; + background-color: transparent; + font-size: 16px; + color: #333; +} + +/* 검색 아이콘 스타일 */ +.search-icon { + width: 20px; + height: 20px; + cursor: pointer; } diff --git a/client/src/components/search/search.js b/client/src/components/search/search.js index 39e40d2..5afb401 100644 --- a/client/src/components/search/search.js +++ b/client/src/components/search/search.js @@ -5,25 +5,37 @@ import "./search.css"; function SearchPage() { const [searchQuery, setSearchQuery] = useState(""); const [data, setData] = useState([]); - + const [filteredData, setFilteredData] = useState([]); + // 데이터 가져오기 useEffect(() => { - axios.get("https://example.com/api/drinks") // 실제 API URL로 대체 + axios + .get("/data/drinks.json") // JSON 파일의 경로로 대체 .then(response => setData(response.data)) .catch(error => console.error("Error fetching data:", error)); }, []); - const filteredData = data.filter(item => - item.name.toLowerCase().includes(searchQuery.toLowerCase()) - ); + const handleSearch = () => { + const results = data.filter(item => + item.name && item.name.toLowerCase().includes(searchQuery.toLowerCase()) + ); + setFilteredData(results); + }; return ( -
+
setSearchQuery(e.target.value)} + className="search-input" + /> + search icon
    {filteredData.map(item => ( diff --git a/client/src/pages/FruitWinePage.js b/client/src/pages/FruitWinePage.js index f5d1ce5..33643e2 100644 --- a/client/src/pages/FruitWinePage.js +++ b/client/src/pages/FruitWinePage.js @@ -9,7 +9,7 @@ const FruitWinePage = () => { return (
    - +
    diff --git a/client/src/pages/mypage.css b/client/src/pages/mypage.css index 7ae2648..958ffa7 100644 --- a/client/src/pages/mypage.css +++ b/client/src/pages/mypage.css @@ -101,6 +101,11 @@ outline: none; /* 포커스 시 테두리도 제거 */ background-color: #f6f6f6; text-align: right; + font-size: 16px; /* 텍스트 입력 크기 */ +} + +.percentage { + font-size: 16px !important; /* 입력 텍스트와 동일한 크기 */ } .preference-score span:first-child { @@ -114,7 +119,13 @@ /* 담은 술 섹션 */ .favorite-alcohol h4 { + margin-bottom: 10px; +} + +.add-btn{ + border: none; margin-bottom: 30px; + cursor: pointer; } .alcohol-grid { @@ -137,11 +148,12 @@ color: #888; } -.alcohol-item.add-more { +/* .alcohol-item.add-more { background-color: #d0d0d0; font-weight: bold; cursor: pointer; } +*/ .alcohol-item.empty { background-color: #f0f0f0; @@ -165,3 +177,9 @@ .profile-info h2 { margin: 0; /* 기본 마진 제거 */ } + +.nickname-error { + color: red; + font-size: 12px; + margin-top: 5px; +} \ No newline at end of file diff --git a/client/src/pages/mypage.js b/client/src/pages/mypage.js index 28f3417..52b860a 100644 --- a/client/src/pages/mypage.js +++ b/client/src/pages/mypage.js @@ -1,17 +1,22 @@ import React, { useState, useRef } from "react"; import "./mypage.css"; // CSS 파일을 불러옵니다 import Header from "../components/common/Header"; +import { useNavigate } from "react-router-dom"; function Mypage() { const [isEditing, setIsEditing] = useState(false); // 편집 모드 상태 const [nickname, setNickname] = useState("Nickname"); // 닉네임 상태 + const [nicknameError, setNicknameError] = useState(""); // 닉네임 오류 메시지 상태 const [preferenceScore, setPreferenceScore] = useState(""); // 선호도수 상태 const [profileImage, setProfileImage] = useState("default-avatar.png"); // 프로필 이미지 상태 + const fileInputRef = useRef(null); // 파일 입력을 위한 ref 생성 + const navigate = useNavigate(); const handleEditClick = () => { setIsEditing(true); // 편집 모드로 변경 + setNicknameError(""); // 편집 모드 들어갈 때 오류 메시지 초기화 }; const handleSaveClick = () => { @@ -19,11 +24,22 @@ function Mypage() { }; const handlePreferenceChange = (e) => { - setPreferenceScore(e.target.value); // 선호도수 상태 업데이트 - }; + // 입력된 값이 숫자만 포함된 값으로 업데이트 + const value = e.target.value; + + if (/^\d*$/.test(value)) { + setPreferenceScore(value); // 숫자만 입력된 경우 상태 업데이트 + } +}; const handleNicknameChange = (e) => { - setNickname(e.target.value); // 닉네임 상태 업데이트 + const newNickname = e.target.value; // 닉네임 상태 업데이트 + if (newNickname.length <= 10) { + setNickname(newNickname); // 닉네임 상태 업데이트 + setNicknameError(""); // 오류 메시지 초기화 + } else { + setNicknameError("글자수가 초과되었습니다"); // 글자수가 초과된 경우 오류 메시지 설정 + } }; const handleImageChange = (e) => { @@ -45,6 +61,15 @@ function Mypage() { fileInputRef.current.click(); // 파일 입력 클릭 }; + const handleNicknameFocus = () => { + setNickname(""); // 입력란 클릭 시 빈 칸으로 설정 + }; + + const handleAddAlcoholClick=()=>{ + navigate("/cheongtakju"); + }; + + return (
    @@ -58,8 +83,10 @@ function Mypage() { + {nicknameError &&

    {nicknameError}

    } {/* 오류 메시지 표시 */}
    +
    @@ -118,13 +152,12 @@ function Mypage() {
    -
    +
    +
- ); } From c9f54d836ab5944f3ef32c3e0fe5dee30c55b89d Mon Sep 17 00:00:00 2001 From: StarrySnowy Date: Thu, 21 Nov 2024 11:10:21 +0100 Subject: [PATCH 03/12] feature searchbar --- client/public/data/drinks.json | 32 +++++++++++++------------- client/src/components/search/search.js | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/client/public/data/drinks.json b/client/public/data/drinks.json index bde43ee..7a73493 100644 --- a/client/public/data/drinks.json +++ b/client/public/data/drinks.json @@ -245,112 +245,112 @@ "preferenceLevel":5.5, "area":"경상남도", "type":"탁주", - "postIamge":"/images/cheongtakju/takju1.jpg" + "postImage":"/images/cheongtakju/takju1.jpg" }, {"drinkName":"가와지탁주", "preferenceLevel":7.5, "area":"경기도", "type":"탁주", - "postIamge":"/images/cheongtakju/takju2.jpg" + "postImage":"/images/cheongtakju/takju2.jpg" }, {"drinkName":"연희유자", "preferenceLevel":10, "area":"서울특별시", "type":"탁주", - "postIamge":"/images/cheongtakju/takju3.jpg" + "postImage":"/images/cheongtakju/takju3.jpg" }, {"drinkName":"팔팔막걸리", "preferenceLevel":6, "area":"경기도", "type":"탁주", - "postIamge":"/images/cheongtakju/takju4.jpg" + "postImage":"/images/cheongtakju/takju4.jpg" }, {"drinkName":"설레 7도", "preferenceLevel":7, "area":"경상남도", "type":"탁주", - "postIamge":"/images/cheongtakju/takju5.jpg" + "postImage":"/images/cheongtakju/takju5.jpg" }, {"drinkName":"보은주", "preferenceLevel":10, "area":"충청북도", "type":"탁주", - "postIamge":"/images/cheongtakju/takju6.jpg" + "postImage":"/images/cheongtakju/takju6.jpg" }, {"drinkName":"바텐더의막걸리", "preferenceLevel":14, "area":"서울특별시", "type":"탁주", - "postIamge":"/images/cheongtakju/takju7.jpg" + "postImage":"/images/cheongtakju/takju7.jpg" }, {"drinkName":"김유정역", "preferenceLevel":6, "area":"강원도", "type":"탁주", - "postIamge":"/images/cheongtakju/takju8.jpg" + "postImage":"/images/cheongtakju/takju8.jpg" }, {"drinkName":"님 그리다", "preferenceLevel":6, "area":"경상남도", "type":"탁주", - "postIamge":"/images/cheongtakju/takju9.jpg" + "postImage":"/images/cheongtakju/takju9.jpg" }, {"drinkName":"일엽편주", "preferenceLevel":12, "area":"경상북도", "type":"탁주", - "postIamge":"/images/cheongtakju/takju10.jpg" + "postImage":"/images/cheongtakju/takju10.jpg" }, {"drinkName":"입장탁주", "preferenceLevel":7, "area":"충청남도", "type":"탁주", - "postIamge":"/images/cheongtakju/takju11.jpg" + "postImage":"/images/cheongtakju/takju11.jpg" }, {"drinkName":"메들리손막걸리", "preferenceLevel":8, "area":"경기도", "type":"탁주", - "postIamge":"/images/cheongtakju/takju12.jpg" + "postImage":"/images/cheongtakju/takju12.jpg" }, {"drinkName":"자작막걸리", "preferenceLevel":12, "area":"강원도", "type":"탁주", - "postIamge":"/images/cheongtakju/takju13.jpg" + "postImage":"/images/cheongtakju/takju13.jpg" }, {"drinkName":"냥이탁주 화이트", "preferenceLevel":10.5, "area":"경기도", "type":"탁주", - "postIamge":"/images/cheongtakju/takju14.jpg" + "postImage":"/images/cheongtakju/takju14.jpg" }, {"drinkName":"대대포9", "preferenceLevel":9, "area":"전라남도", "type":"탁주", - "postIamge":"/images/cheongtakju/takju15.jpg" + "postImage":"/images/cheongtakju/takju15.jpg" }, {"drinkName":"아임프리6.0", "preferenceLevel":6, "area":"경기도", "type":"탁주", - "postIamge":"/images/cheongtakju/takju16.jpg" + "postImage":"/images/cheongtakju/takju16.jpg" }, {"drinkName":"냥이탁주 9도", diff --git a/client/src/components/search/search.js b/client/src/components/search/search.js index 5afb401..0a41ad4 100644 --- a/client/src/components/search/search.js +++ b/client/src/components/search/search.js @@ -17,8 +17,8 @@ function SearchPage() { const handleSearch = () => { const results = data.filter(item => - item.name && item.name.toLowerCase().includes(searchQuery.toLowerCase()) - ); + item.drinkName && item.drinkName.toLowerCase().includes(searchQuery.toLowerCase()) + ); setFilteredData(results); }; From 1fc4496881e81dc057939732e87d9013f1d40138 Mon Sep 17 00:00:00 2001 From: StarrySnowy Date: Thu, 21 Nov 2024 12:51:57 +0100 Subject: [PATCH 04/12] feature: search --- client/src/api/searchapi.js | 29 +++++++++++++++ client/src/components/search/search.js | 49 ++++++++++++++++++-------- 2 files changed, 64 insertions(+), 14 deletions(-) create mode 100644 client/src/api/searchapi.js diff --git a/client/src/api/searchapi.js b/client/src/api/searchapi.js new file mode 100644 index 0000000..d21ce56 --- /dev/null +++ b/client/src/api/searchapi.js @@ -0,0 +1,29 @@ +import axios from "axios"; + +// Axios 인스턴스 생성 +const apiClient = axios.create({ + baseURL: process.env.REACT_APP_API_ROUTE, // .env에서 설정한 baseURL 사용 +}); + +const searchapi = async (drinkName, page) => { + try { + const response = await apiClient.get(`/api/post/search`, { + params: { + drinkName: encodeURIComponent(drinkName), // URL 인코딩된 drinkName 전달 + page, + }, + }); + + // 성공 응답을 반환, 데이터는 response.data.data.postDtos + if (response.data.code === "200") { + return response.data.data.postDtos; // 필요한 데이터 반환 + } else { + throw new Error(response.data.message || "전통주 검색 실패"); + } + } catch (error) { + console.error("API 호출 중 에러 발생:", error.message); + throw error; // 에러를 호출한 곳에서 처리하도록 전달 + } +}; + +export default searchapi; diff --git a/client/src/components/search/search.js b/client/src/components/search/search.js index 0a41ad4..22a6519 100644 --- a/client/src/components/search/search.js +++ b/client/src/components/search/search.js @@ -1,25 +1,38 @@ import React, { useState, useEffect } from "react"; -import axios from "axios"; +import searchapi from "../../api/searchapi"; import "./search.css"; function SearchPage() { const [searchQuery, setSearchQuery] = useState(""); - const [data, setData] = useState([]); const [filteredData, setFilteredData] = useState([]); + const [page, setPage] = useState(1); // 페이지 상태 추가 + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); - // 데이터 가져오기 + // API로부터 데이터를 검색해서 필터링하는 함수 + const fetchData = async () => { + try { + setLoading(true); + setError(null); + const result = await searchapi(searchQuery, page); + setFilteredData(result); // 검색 결과를 업데이트 + } catch (error) { + setError("검색 중 문제가 발생했습니다."); + } finally { + setLoading(false); + } + }; + + // searchQuery가 변경되거나 페이지가 바뀔 때마다 fetchData 호출 useEffect(() => { - axios - .get("/data/drinks.json") // JSON 파일의 경로로 대체 - .then(response => setData(response.data)) - .catch(error => console.error("Error fetching data:", error)); - }, []); + if (searchQuery.trim() !== "") { + fetchData(); + } + }, [searchQuery, page]); const handleSearch = () => { - const results = data.filter(item => - item.drinkName && item.drinkName.toLowerCase().includes(searchQuery.toLowerCase()) - ); - setFilteredData(results); + setPage(1); // 새 검색 시 페이지를 1로 리셋 + fetchData(); }; return ( @@ -37,9 +50,17 @@ function SearchPage() { onClick={handleSearch} // 돋보기 클릭 시 데이터 필터링 결과 출력 className="search-icon" /> + {loading &&

검색 중...

} + {error &&

{error}

}
    - {filteredData.map(item => ( -
  • {item.name}
  • + {filteredData.map((item, index) => ( +
  • +
    {item.drinkName}
    +
    {item.preferenceLevel}
    +
    {item.area}
    +
    {item.type}
    + {item.drinkName} +
  • ))}
From 2ab12859ec89cefdb87cdde02387d92ec3436f9e Mon Sep 17 00:00:00 2001 From: StarrySnowy Date: Thu, 21 Nov 2024 13:18:36 +0100 Subject: [PATCH 05/12] =?UTF-8?q?searchbar=EC=88=98=EC=A0=951?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/api/searchapi.js | 2 +- client/src/components/search/search.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/client/src/api/searchapi.js b/client/src/api/searchapi.js index d21ce56..899d29f 100644 --- a/client/src/api/searchapi.js +++ b/client/src/api/searchapi.js @@ -7,7 +7,7 @@ const apiClient = axios.create({ const searchapi = async (drinkName, page) => { try { - const response = await apiClient.get(`/api/post/search`, { + const response = await apiClient.get(`/api/post/search?drinkName=${drinkName}&page=${page}`, { params: { drinkName: encodeURIComponent(drinkName), // URL 인코딩된 drinkName 전달 page, diff --git a/client/src/components/search/search.js b/client/src/components/search/search.js index 22a6519..c153597 100644 --- a/client/src/components/search/search.js +++ b/client/src/components/search/search.js @@ -15,6 +15,7 @@ function SearchPage() { setLoading(true); setError(null); const result = await searchapi(searchQuery, page); + console.log(result); // 데이터가 제대로 오는지 확인 setFilteredData(result); // 검색 결과를 업데이트 } catch (error) { setError("검색 중 문제가 발생했습니다."); From c805d86e4324fbebcf0c54775470b8559fad9de1 Mon Sep 17 00:00:00 2001 From: StarrySnowy Date: Thu, 21 Nov 2024 13:40:23 +0100 Subject: [PATCH 06/12] search --- client/src/api/mypage.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 client/src/api/mypage.js diff --git a/client/src/api/mypage.js b/client/src/api/mypage.js new file mode 100644 index 0000000..96a6532 --- /dev/null +++ b/client/src/api/mypage.js @@ -0,0 +1,25 @@ +import axios from "axios"; + +// Axios 인스턴스 생성 +const apiClient = axios.create({ + baseURL: process.env.REACT_APP_API_ROUTE, // .env에서 설정한 baseURL 사용 +}); + +const getMypageInfo = async () => { + try { + // API 호출 + const response = await apiClient.get("/api/mypage/info"); + + // 성공적으로 데이터를 받아왔다면 + if (response.data.code === "200") { + return response.data.data; // 필요한 데이터 반환 + } else { + throw new Error(response.data.message || "마이페이지 정보를 불러오지 못했습니다."); + } + } catch (error) { + console.error("API 호출 중 에러 발생:", error.message); + throw error; // 에러를 호출한 곳에서 처리하도록 전달 + } +}; + +export default getMypageInfo; From 8a9c87eddc86b63a8aa18d5edd339af759563371 Mon Sep 17 00:00:00 2001 From: StarrySnowy Date: Mon, 25 Nov 2024 15:57:21 +0100 Subject: [PATCH 07/12] feature:search --- client/public/images/search-icon.jpg | Bin 0 -> 61664 bytes client/src/api/searchapi.js | 17 +++---- client/src/components/search/search.js | 63 +++++++++++++++---------- 3 files changed, 43 insertions(+), 37 deletions(-) create mode 100644 client/public/images/search-icon.jpg diff --git a/client/public/images/search-icon.jpg b/client/public/images/search-icon.jpg new file mode 100644 index 0000000000000000000000000000000000000000..885905a4b14092a258db51aad0e69f97e4caf569 GIT binary patch literal 61664 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 M{8nWv2>plrKio9-qW}N^ literal 0 HcmV?d00001 diff --git a/client/src/api/searchapi.js b/client/src/api/searchapi.js index 899d29f..d3d33dc 100644 --- a/client/src/api/searchapi.js +++ b/client/src/api/searchapi.js @@ -2,27 +2,22 @@ import axios from "axios"; // Axios 인스턴스 생성 const apiClient = axios.create({ - baseURL: process.env.REACT_APP_API_ROUTE, // .env에서 설정한 baseURL 사용 + baseURL: process.env.REACT_APP_API_ROUTE, // .env에 설정된 baseURL }); -const searchapi = async (drinkName, page) => { +const searchapi = async (drinkName) => { try { - const response = await apiClient.get(`/api/post/search?drinkName=${drinkName}&page=${page}`, { - params: { - drinkName: encodeURIComponent(drinkName), // URL 인코딩된 drinkName 전달 - page, - }, - }); + const response = await apiClient.get(`/api/post/search?drinkName=${encodeURIComponent(drinkName)}`); - // 성공 응답을 반환, 데이터는 response.data.data.postDtos + // 성공 응답 처리 if (response.data.code === "200") { - return response.data.data.postDtos; // 필요한 데이터 반환 + return response.data.data.postDtos; // 검색 결과 반환 } else { throw new Error(response.data.message || "전통주 검색 실패"); } } catch (error) { console.error("API 호출 중 에러 발생:", error.message); - throw error; // 에러를 호출한 곳에서 처리하도록 전달 + throw error; // 에러를 상위 호출로 전달 } }; diff --git a/client/src/components/search/search.js b/client/src/components/search/search.js index c153597..c137996 100644 --- a/client/src/components/search/search.js +++ b/client/src/components/search/search.js @@ -1,22 +1,25 @@ -import React, { useState, useEffect } from "react"; +import React, { useState } from "react"; import searchapi from "../../api/searchapi"; import "./search.css"; function SearchPage() { const [searchQuery, setSearchQuery] = useState(""); const [filteredData, setFilteredData] = useState([]); - const [page, setPage] = useState(1); // 페이지 상태 추가 const [loading, setLoading] = useState(false); const [error, setError] = useState(null); + const [page, setPage] = useState(1); // page 상태 추가 - // API로부터 데이터를 검색해서 필터링하는 함수 const fetchData = async () => { try { setLoading(true); setError(null); - const result = await searchapi(searchQuery, page); - console.log(result); // 데이터가 제대로 오는지 확인 - setFilteredData(result); // 검색 결과를 업데이트 + const result = await searchapi(searchQuery, page); // page를 포함한 API 호출 + console.log(result); // API 응답 확인 + if (result && Array.isArray(result)) { + setFilteredData(result); // 정상적인 데이터만 업데이트 + } else { + setFilteredData([]); // 잘못된 데이터일 경우 빈 배열로 처리 + } } catch (error) { setError("검색 중 문제가 발생했습니다."); } finally { @@ -24,18 +27,21 @@ function SearchPage() { } }; - // searchQuery가 변경되거나 페이지가 바뀔 때마다 fetchData 호출 - useEffect(() => { - if (searchQuery.trim() !== "") { - fetchData(); - } - }, [searchQuery, page]); - const handleSearch = () => { - setPage(1); // 새 검색 시 페이지를 1로 리셋 + if (searchQuery.trim() === "") { + setError("검색어를 입력해주세요."); // 검색어가 비어있으면 에러 처리 + return; + } + setPage(1); // 검색할 때마다 페이지를 1로 초기화 fetchData(); }; + const handleKeyPress = (e) => { + if (e.key === "Enter") { + handleSearch(); // 엔터 키 입력 시 검색 실행 + } + }; + return (
setSearchQuery(e.target.value)} + onKeyDown={handleKeyPress} className="search-input" /> - search icon {loading &&

검색 중...

} {error &&

{error}

}
    - {filteredData.map((item, index) => ( -
  • -
    {item.drinkName}
    -
    {item.preferenceLevel}
    -
    {item.area}
    -
    {item.type}
    - {item.drinkName} -
  • - ))} + {Array.isArray(filteredData) && filteredData.length > 0 ? ( + filteredData.map((item, index) => ( +
  • +
    {item.drinkName}
    +
    {item.preferenceLevel}
    +
    {item.area}
    +
    {item.type}
    + {item.drinkName} +
  • + )) + ) : ( +

    검색 결과가 없습니다.

    + )}
); From 5d063e22ea9c47c23b610c96de838825395370bc Mon Sep 17 00:00:00 2001 From: StarrySnowy Date: Mon, 25 Nov 2024 16:30:02 +0100 Subject: [PATCH 08/12] feature: mypageapi --- client/src/api/mypage.js | 25 ---------- client/src/api/mypageapi.js | 92 +++++++++++++++++++++++++++++++++++++ client/src/pages/mypage.js | 91 +++++++++++++++++++++++------------- 3 files changed, 152 insertions(+), 56 deletions(-) delete mode 100644 client/src/api/mypage.js create mode 100644 client/src/api/mypageapi.js diff --git a/client/src/api/mypage.js b/client/src/api/mypage.js deleted file mode 100644 index 96a6532..0000000 --- a/client/src/api/mypage.js +++ /dev/null @@ -1,25 +0,0 @@ -import axios from "axios"; - -// Axios 인스턴스 생성 -const apiClient = axios.create({ - baseURL: process.env.REACT_APP_API_ROUTE, // .env에서 설정한 baseURL 사용 -}); - -const getMypageInfo = async () => { - try { - // API 호출 - const response = await apiClient.get("/api/mypage/info"); - - // 성공적으로 데이터를 받아왔다면 - if (response.data.code === "200") { - return response.data.data; // 필요한 데이터 반환 - } else { - throw new Error(response.data.message || "마이페이지 정보를 불러오지 못했습니다."); - } - } catch (error) { - console.error("API 호출 중 에러 발생:", error.message); - throw error; // 에러를 호출한 곳에서 처리하도록 전달 - } -}; - -export default getMypageInfo; diff --git a/client/src/api/mypageapi.js b/client/src/api/mypageapi.js new file mode 100644 index 0000000..5229174 --- /dev/null +++ b/client/src/api/mypageapi.js @@ -0,0 +1,92 @@ +import axios from "axios"; + +// Axios 인스턴스 생성 +const apiClient = axios.create({ + baseURL: process.env.REACT_APP_API_ROUTE, // .env에서 설정한 baseURL 사용 +}); + +// 1. 내 정보 확인 +const getUserInfo = async () => { + try { + const response = await apiClient.get("/api/mypage/info"); + if (response.data.code === "200") { + return response.data.data; // 내 정보 반환 + } else { + throw new Error(response.data.message || "내 정보 조회 실패"); + } + } catch (error) { + console.error("내 정보 조회 중 에러 발생:", error.message); + throw error; + } +}; + +// 2. 북마크 확인 +const getUserBookmarks = async () => { + try { + const response = await apiClient.get("/api/mypage/bookmarks"); + if (response.data.code === "200") { + return response.data.data; // 북마크 반환 + } else { + throw new Error(response.data.message || "북마크 조회 실패"); + } + } catch (error) { + console.error("북마크 조회 중 에러 발생:", error.message); + throw error; + } +}; + +// 3. 이름 수정 +const updateUserInfo = async (name) => { + try { + const response = await apiClient.post("/api/mypage/updateInfo", { + name, + }); + if (response.data.code === "200") { + return response.data.data; // 수정된 정보 반환 + } else { + throw new Error(response.data.message || "이름 수정 실패"); + } + } catch (error) { + console.error("이름 수정 중 에러 발생:", error.message); + throw error; + } +}; + +// 4. 선호 도수 설정 +const updateUserPreference = async (preference) => { + try { + const response = await apiClient.post("/api/mypage/updatePreference", { + preference, + }); + if (response.data.code === "200") { + return response.data.data; // 선호도수 설정 결과 반환 + } else { + throw new Error(response.data.message || "선호도수 설정 실패"); + } + } catch (error) { + console.error("선호도수 설정 중 에러 발생:", error.message); + throw error; + } +}; + +// 5. 프로필 사진 수정 +const updateUserProfileImage = async (formData) => { + try { + const response = await apiClient.post("/api/mypage/updateProfileImage", formData, { + headers: { + "Content-Type": "multipart/form-data", // 이미지 업로드를 위한 헤더 설정 + }, + }); + if (response.data.code === "200") { + return response.data.data; // 프로필 사진 수정 결과 반환 + } else { + throw new Error(response.data.message || "프로필 사진 수정 실패"); + } + } catch (error) { + console.error("프로필 사진 수정 중 에러 발생:", error.message); + throw error; + } +}; + +// API 함수들을 export +export { getUserInfo, getUserBookmarks, updateUserInfo, updateUserPreference, updateUserProfileImage }; diff --git a/client/src/pages/mypage.js b/client/src/pages/mypage.js index 52b860a..05e17b1 100644 --- a/client/src/pages/mypage.js +++ b/client/src/pages/mypage.js @@ -1,7 +1,8 @@ -import React, { useState, useRef } from "react"; +import React, { useState, useRef, useEffect } from "react"; import "./mypage.css"; // CSS 파일을 불러옵니다 import Header from "../components/common/Header"; import { useNavigate } from "react-router-dom"; +import { getUserInfo, getUserBookmarks, updateUserInfo, updateUserPreference, updateUserProfileImage } from "../api/mypageapi"; // API 함수 import function Mypage() { const [isEditing, setIsEditing] = useState(false); // 편집 모드 상태 @@ -9,31 +10,53 @@ function Mypage() { const [nicknameError, setNicknameError] = useState(""); // 닉네임 오류 메시지 상태 const [preferenceScore, setPreferenceScore] = useState(""); // 선호도수 상태 const [profileImage, setProfileImage] = useState("default-avatar.png"); // 프로필 이미지 상태 - - const fileInputRef = useRef(null); // 파일 입력을 위한 ref 생성 const navigate = useNavigate(); + // 페이지 로딩 시 사용자 정보 가져오기 + useEffect(() => { + const fetchUserInfo = async () => { + try { + const userInfo = await getUserInfo(); + setNickname(userInfo.nickname); + setPreferenceScore(userInfo.preference || ""); + setProfileImage(userInfo.profileImage || "default-avatar.png"); + } catch (error) { + console.error("사용자 정보 조회 중 오류 발생:", error.message); + } + }; + + fetchUserInfo(); + }, []); + const handleEditClick = () => { setIsEditing(true); // 편집 모드로 변경 setNicknameError(""); // 편집 모드 들어갈 때 오류 메시지 초기화 }; - const handleSaveClick = () => { + const handleSaveClick = async () => { setIsEditing(false); // 편집 모드 해제 - }; - const handlePreferenceChange = (e) => { - // 입력된 값이 숫자만 포함된 값으로 업데이트 - const value = e.target.value; - - if (/^\d*$/.test(value)) { - setPreferenceScore(value); // 숫자만 입력된 경우 상태 업데이트 - } -}; + try { + // 닉네임 수정 + if (nickname !== "") { + await updateUserInfo(nickname); + } + // 선호 도수 설정 + if (preferenceScore !== "") { + await updateUserPreference(preferenceScore); + } + // 프로필 사진 수정 + if (profileImage !== "default-avatar.png") { + await updateUserProfileImage(profileImage); + } + } catch (error) { + console.error("수정 중 오류 발생:", error.message); + } + }; const handleNicknameChange = (e) => { - const newNickname = e.target.value; // 닉네임 상태 업데이트 + const newNickname = e.target.value; if (newNickname.length <= 10) { setNickname(newNickname); // 닉네임 상태 업데이트 setNicknameError(""); // 오류 메시지 초기화 @@ -42,6 +65,14 @@ function Mypage() { } }; + const handlePreferenceChange = (e) => { + const value = e.target.value; + + if (/^\d*$/.test(value)) { + setPreferenceScore(value); // 숫자만 입력된 경우 상태 업데이트 + } + }; + const handleImageChange = (e) => { const file = e.target.files[0]; // 선택된 파일 if (file) { @@ -62,14 +93,13 @@ function Mypage() { }; const handleNicknameFocus = () => { - setNickname(""); // 입력란 클릭 시 빈 칸으로 설정 + setNickname(""); // 입력란 클릭 시 빈 칸으로 설정 }; - const handleAddAlcoholClick=()=>{ + const handleAddAlcoholClick = () => { navigate("/cheongtakju"); }; - return (
@@ -86,7 +116,7 @@ function Mypage() { onFocus={handleNicknameFocus} // 클릭 시 빈 칸으로 설정 className="nickname-input" /> - {nicknameError &&

{nicknameError}

} {/* 오류 메시지 표시 */} + {nicknameError &&

{nicknameError}

}
-
-
-
-
-
-
- {/* 두 번째 줄 */} -
-
-
-
-
+
+
+
+
+
+
+ {/* 두 번째 줄 */} +
+
+
+
+ ); } From 878bbdc7a2707abf334a60fcae786fec9789dce1 Mon Sep 17 00:00:00 2001 From: StarrySnowy Date: Tue, 26 Nov 2024 11:49:29 +0100 Subject: [PATCH 09/12] =?UTF-8?q?feature:=20search=EA=B2=B0=EA=B3=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/api/searchapi.js | 5 +++-- client/src/components/search/search.js | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/client/src/api/searchapi.js b/client/src/api/searchapi.js index d3d33dc..21c4782 100644 --- a/client/src/api/searchapi.js +++ b/client/src/api/searchapi.js @@ -7,11 +7,12 @@ const apiClient = axios.create({ const searchapi = async (drinkName) => { try { - const response = await apiClient.get(`/api/post/search?drinkName=${encodeURIComponent(drinkName)}`); + const response = await apiClient.get(`/api/post/search?drinkName=${drinkName}`); // 성공 응답 처리 if (response.data.code === "200") { - return response.data.data.postDtos; // 검색 결과 반환 + console.log(response) + return response.data.data.searchResult.content; // 검색 결과 반환 } else { throw new Error(response.data.message || "전통주 검색 실패"); } diff --git a/client/src/components/search/search.js b/client/src/components/search/search.js index c137996..00d24af 100644 --- a/client/src/components/search/search.js +++ b/client/src/components/search/search.js @@ -13,7 +13,7 @@ function SearchPage() { try { setLoading(true); setError(null); - const result = await searchapi(searchQuery, page); // page를 포함한 API 호출 + const result = await searchapi(searchQuery); // page를 포함한 API 호출 console.log(result); // API 응답 확인 if (result && Array.isArray(result)) { setFilteredData(result); // 정상적인 데이터만 업데이트 From b0a2077f86a4bc62398a293a69a2b2cc37a507f0 Mon Sep 17 00:00:00 2001 From: StarrySnowy Date: Tue, 26 Nov 2024 12:44:21 +0100 Subject: [PATCH 10/12] feature : search --- client/src/App.js | 4 ++ client/src/components/search/search.js | 47 +++--------------- client/src/pages/searchresult.js | 66 ++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 41 deletions(-) create mode 100644 client/src/pages/searchresult.js diff --git a/client/src/App.js b/client/src/App.js index 6320009..ced85c5 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -5,6 +5,8 @@ import FruitWinePage from "./pages/FruitWinePage"; import SignInPage from "./pages/SignInPage"; import Mypage from "./pages/mypage"; import SignUpPage from "./pages/SignUpPage"; +import SearchPage from "./components/search/search"; +import ResultsPage from "./pages/searchresult"; import { BrowserRouter, Router, Route, Routes, Link } from "react-router-dom"; function App() { @@ -18,6 +20,8 @@ function App() { } /> } /> } /> + } /> + } /> diff --git a/client/src/components/search/search.js b/client/src/components/search/search.js index 00d24af..4b6214a 100644 --- a/client/src/components/search/search.js +++ b/client/src/components/search/search.js @@ -1,44 +1,25 @@ import React, { useState } from "react"; -import searchapi from "../../api/searchapi"; +import { useNavigate } from "react-router-dom"; import "./search.css"; function SearchPage() { const [searchQuery, setSearchQuery] = useState(""); - const [filteredData, setFilteredData] = useState([]); - const [loading, setLoading] = useState(false); const [error, setError] = useState(null); - const [page, setPage] = useState(1); // page 상태 추가 - - const fetchData = async () => { - try { - setLoading(true); - setError(null); - const result = await searchapi(searchQuery); // page를 포함한 API 호출 - console.log(result); // API 응답 확인 - if (result && Array.isArray(result)) { - setFilteredData(result); // 정상적인 데이터만 업데이트 - } else { - setFilteredData([]); // 잘못된 데이터일 경우 빈 배열로 처리 - } - } catch (error) { - setError("검색 중 문제가 발생했습니다."); - } finally { - setLoading(false); - } - }; + const navigate = useNavigate(); const handleSearch = () => { if (searchQuery.trim() === "") { setError("검색어를 입력해주세요."); // 검색어가 비어있으면 에러 처리 return; } - setPage(1); // 검색할 때마다 페이지를 1로 초기화 - fetchData(); + setError(null); + // 검색 결과 페이지로 이동, 쿼리 파라미터에 검색어 전달 + navigate(`/results?query=${encodeURIComponent(searchQuery)}`); }; const handleKeyPress = (e) => { if (e.key === "Enter") { - handleSearch(); // 엔터 키 입력 시 검색 실행 + handleSearch(); } }; @@ -58,23 +39,7 @@ function SearchPage() { onClick={handleSearch} className="search-icon" /> - {loading &&

검색 중...

} {error &&

{error}

} -
    - {Array.isArray(filteredData) && filteredData.length > 0 ? ( - filteredData.map((item, index) => ( -
  • -
    {item.drinkName}
    -
    {item.preferenceLevel}
    -
    {item.area}
    -
    {item.type}
    - {item.drinkName} -
  • - )) - ) : ( -

    검색 결과가 없습니다.

    - )} -
); } diff --git a/client/src/pages/searchresult.js b/client/src/pages/searchresult.js new file mode 100644 index 0000000..e7a099e --- /dev/null +++ b/client/src/pages/searchresult.js @@ -0,0 +1,66 @@ +import React, { useState, useEffect } from "react"; +import { useLocation } from "react-router-dom"; +import searchapi from "../api/searchapi"; +import Header from "../components/common/Header"; +import SearchPage from "../components/search/search"; +import Footer from "../components/common/Footer"; + + +function ResultsPage() { + const location = useLocation(); + const queryParams = new URLSearchParams(location.search); + const searchQuery = queryParams.get("query"); + + const [filteredData, setFilteredData] = useState([]); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + useEffect(() => { + const fetchData = async () => { + try { + setLoading(true); + setError(null); + const result = await searchapi(searchQuery); + setFilteredData(result || []); + } catch (err) { + setError("검색 중 문제가 발생했습니다."); + } finally { + setLoading(false); + } + }; + + if (searchQuery) { + fetchData(); + } + }, [searchQuery]); + + return ( +
+
+ +
+

검색 결과: {searchQuery}

+ {loading &&

검색 중...

} + {error &&

{error}

} +
    + {filteredData.length > 0 ? ( + filteredData.map((item, index) => ( +
  • +
    {item.drinkName}
    +
    {item.preferenceLevel}
    +
    {item.area}
    +
    {item.type}
    + {item.drinkName} +
  • + )) + ) : ( +

    검색 결과가 없습니다.

    + )} +
+
+
+
+ ); +} + +export default ResultsPage; From 7a3c78e486a1e5498e2d8dc3bc8894b7b79f1b46 Mon Sep 17 00:00:00 2001 From: StarrySnowy Date: Tue, 26 Nov 2024 14:29:39 +0100 Subject: [PATCH 11/12] feature:searchresult --- client/src/pages/searchresult.css | 17 +++++++++++++++++ client/src/pages/searchresult.js | 1 + 2 files changed, 18 insertions(+) create mode 100644 client/src/pages/searchresult.css diff --git a/client/src/pages/searchresult.css b/client/src/pages/searchresult.css new file mode 100644 index 0000000..e48d11e --- /dev/null +++ b/client/src/pages/searchresult.css @@ -0,0 +1,17 @@ +.results-container ul { + list-style: none; + padding: 0; + } + + .results-container li { + margin: 10px 0; + padding: 10px; + border: 1px solid #ddd; + border-radius: 5px; + } + + .results-container img { + max-width: 100px; + height: auto; + border-radius: 5px; + } \ No newline at end of file diff --git a/client/src/pages/searchresult.js b/client/src/pages/searchresult.js index e7a099e..aebae7d 100644 --- a/client/src/pages/searchresult.js +++ b/client/src/pages/searchresult.js @@ -4,6 +4,7 @@ import searchapi from "../api/searchapi"; import Header from "../components/common/Header"; import SearchPage from "../components/search/search"; import Footer from "../components/common/Footer"; +import "./searchresult.css"; function ResultsPage() { From ddd3df58774c32b47dedd2f182d28638f0947403 Mon Sep 17 00:00:00 2001 From: StarrySnowy Date: Tue, 26 Nov 2024 14:55:39 +0100 Subject: [PATCH 12/12] feature:searchresult --- client/src/pages/searchresult.css | 106 +++++++++++++++++++++++++----- 1 file changed, 89 insertions(+), 17 deletions(-) diff --git a/client/src/pages/searchresult.css b/client/src/pages/searchresult.css index e48d11e..d980110 100644 --- a/client/src/pages/searchresult.css +++ b/client/src/pages/searchresult.css @@ -1,17 +1,89 @@ -.results-container ul { - list-style: none; - padding: 0; - } - - .results-container li { - margin: 10px 0; - padding: 10px; - border: 1px solid #ddd; - border-radius: 5px; - } - - .results-container img { - max-width: 100px; - height: auto; - border-radius: 5px; - } \ No newline at end of file +.AlcoholList { + display: flex; + flex-direction: column; + justify-content: center; + margin: 5%; + align-items: center; +} + +.alcohol-container { + display: grid; + grid-template-columns: repeat(5, 1fr); /* 5열 */ + gap: 3%; /* 아이템 간격 */ + width: 75%; +} + +.alcohol-item-wrap { + display: flex; + flex-direction: column; /* 이미지와 텍스트 수직 정렬 */ + align-items: center; + text-align: center; + padding: 10px; + text-decoration: none; +} + +.alcohol-image { + width: 100%; + height: auto; + aspect-ratio: 5 / 6; + object-fit: contain; + border-radius: 8px; + background-color: rgb(239, 239, 239); +} + +.alcohol-name { + margin-top: 8px; + font-size: 13px; + font-weight: bold; + color: rgb(78, 75, 69); + + min-width: 100px; + max-width: 100px; /* 부모 요소 너비 제한 */ +} + +.alcohol-image:hover, +.alcohol-name:hover { + cursor: pointer; +} + +.link-img-tag, +.link-name-tag { + text-decoration: none; + color: inherit; + display: inline-block; +} + +/* 페이지네이션 CSS */ +.pagination { + display: flex; + justify-content: center; + align-items: center; + margin-top: 3%; +} + +.pagination button { + margin: 0 5px; + padding: 8px 12px; + font-size: 14px; + cursor: pointer; + border: none; + background-color: rgba(255, 255, 255, 0); + border-radius: 4px; + transition: background-color 0.3s; +} + +.pagination button:hover { + background-color: rgba(75, 72, 68, 0.445); + color: white; +} + +.pagination button:disabled { + cursor: not-allowed; + opacity: 0.5; +} + +.pagination .active-page { + font-weight: bold; + background-color: rgba(255, 255, 255, 0); + color: rgb(0, 0, 0); +}