Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/241121 #68

Open
wants to merge 13 commits into
base: feature/searchFinal
Choose a base branch
from
705 changes: 705 additions & 0 deletions client/public/data/drinks.json

Large diffs are not rendered by default.

Binary file added client/public/images/search-icon.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions client/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -18,6 +20,8 @@ function App() {
<Route path="/signIn" element={<SignInPage />} />
<Route path="/signUp" element={<SignUpPage />} />
<Route path="/mypage" element={<Mypage />} />
<Route path="/" element={<SearchPage />} />
<Route path="/results" element={<ResultsPage />} />
</Routes>
</BrowserRouter>
</>
Expand Down
92 changes: 92 additions & 0 deletions client/src/api/mypageapi.js
Original file line number Diff line number Diff line change
@@ -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 };
25 changes: 25 additions & 0 deletions client/src/api/searchapi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import axios from "axios";

// Axios 인스턴스 생성
const apiClient = axios.create({
baseURL: process.env.REACT_APP_API_ROUTE, // .env에 설정된 baseURL
});

const searchapi = async (drinkName) => {
try {
const response = await apiClient.get(`/api/post/search?drinkName=${drinkName}`);

// 성공 응답 처리
if (response.data.code === "200") {
console.log(response)
return response.data.data.searchResult.content; // 검색 결과 반환
} else {
throw new Error(response.data.message || "전통주 검색 실패");
}
} catch (error) {
console.error("API 호출 중 에러 발생:", error.message);
throw error; // 에러를 상위 호출로 전달
}
};

export default searchapi;
92 changes: 27 additions & 65 deletions client/src/components/search/search.css
Original file line number Diff line number Diff line change
@@ -1,67 +1,29 @@
/* 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;
}

display: flex;
align-items: center;
justify-content: center; /* 수평 중앙 정렬 */
background-color: #d6d1c9;
border-radius: 20px;
padding: 10px 15px;
max-width: 600px;
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;
}
51 changes: 31 additions & 20 deletions client/src/components/search/search.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,45 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import "./search.css";

function SearchPage() {
const [searchQuery, setSearchQuery] = useState("");
const [data, setData] = useState([]);

// 데이터 가져오기
useEffect(() => {
axios.get("https://example.com/api/drinks") // 실제 API URL로 대체
.then(response => setData(response.data))
.catch(error => console.error("Error fetching data:", error));
}, []);
const [error, setError] = useState(null);
const navigate = useNavigate();

const filteredData = data.filter(item =>
item.name.toLowerCase().includes(searchQuery.toLowerCase())
);
const handleSearch = () => {
if (searchQuery.trim() === "") {
setError("검색어를 입력해주세요."); // 검색어가 비어있으면 에러 처리
return;
}
setError(null);
// 검색 결과 페이지로 이동, 쿼리 파라미터에 검색어 전달
navigate(`/results?query=${encodeURIComponent(searchQuery)}`);
};

const handleKeyPress = (e) => {
if (e.key === "Enter") {
handleSearch();
}
};

return (
<div>
<div className="search-container">
<input
type="text"
placeholder="검색어를 입력하세요"
placeholder="원하는 술을 검색해 보세요!"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
onKeyDown={handleKeyPress}
className="search-input"
/>
<img
src="/images/search-icon.png"
alt="search icon"
onClick={handleSearch}
className="search-icon"
/>
<ul>
{filteredData.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
{error && <p>{error}</p>}
</div>
);
}
Expand Down
3 changes: 2 additions & 1 deletion client/src/pages/CheongtakjuPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<div>
<Header />
<SearchBar />
<SearchPage />
<AlcoholList fetchApi={cheongTakjuListApi} />
<Footer />
</div>
Expand Down
3 changes: 2 additions & 1 deletion client/src/pages/FruitWinePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<div>
<Header />
<SearchBar />
<SearchPage />
<AlcoholList fetchApi={fruitWineListApi} />
<Footer />
</div>
Expand Down
20 changes: 19 additions & 1 deletion client/src/pages/mypage.css
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -114,7 +119,13 @@

/* 담은 술 섹션 */
.favorite-alcohol h4 {
margin-bottom: 10px;
}

.add-btn{
border: none;
margin-bottom: 30px;
cursor: pointer;
}

.alcohol-grid {
Expand All @@ -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;
Expand All @@ -165,3 +177,9 @@
.profile-info h2 {
margin: 0; /* 기본 마진 제거 */
}

.nickname-error {
color: red;
font-size: 12px;
margin-top: 5px;
}
Loading