From 26fbdba9dc1a3de036b7d03ab641ea6530cddb27 Mon Sep 17 00:00:00 2001 From: hyerin11 Date: Tue, 6 Aug 2024 12:01:16 +0900 Subject: [PATCH 1/8] =?UTF-8?q?#=20db=EA=B0=92=20=EB=B0=9B=EC=95=84?= =?UTF-8?q?=EC=98=A4=EA=B8=B0=20=EC=84=B1=EA=B3=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/mainPage/FoodNav.js | 10 +++++++--- src/pages/userMain/CategoriesPage.js | 18 ++++++++++-------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/components/mainPage/FoodNav.js b/src/components/mainPage/FoodNav.js index 20c85d71..241de2ce 100644 --- a/src/components/mainPage/FoodNav.js +++ b/src/components/mainPage/FoodNav.js @@ -14,9 +14,13 @@ const getRandomStores = (stores, count) => { // ๐ŸŒฟ ์นดํ…Œ๊ณ ๋ฆฌ ๋ฌธ์ž์—ด์—์„œ ์‹ค์ œ foodType๋งŒ ์ถ”์ถœํ•˜๋Š” ํ•จ์ˆ˜ const extractFoodType = (category) => { - // category ๋ฌธ์ž์—ด์—์„œ 'foodType=' ์ดํ›„์˜ ๊ฐ’์„ ์ถ”์ถœ - const match = category.match(/\(foodType=(.*?)\)/); - return match ? match[1] : category; // ์ถ”์ถœ๋œ foodType ๋˜๋Š” ์›๋ž˜ ๋ฌธ์ž์—ด ๋ฐ˜ํ™˜ + // category๊ฐ€ ์œ ํšจํ•œ ๋ฌธ์ž์—ด์ธ์ง€ ํ™•์ธ + if (category && typeof category === 'string') { + // 'foodType=' ์ดํ›„์˜ ๊ฐ’ ์ถ”์ถœ + const match = category.match(/\(foodType=(.*?)\)/); + return match ? match[1] : category; + } + return ''; // category๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋นˆ ๋ฌธ์ž์—ด ๋ฐ˜ํ™˜ }; const FoodNav = ({ selectedCategory, stores }) => { diff --git a/src/pages/userMain/CategoriesPage.js b/src/pages/userMain/CategoriesPage.js index f49f75d6..ecaa72d1 100644 --- a/src/pages/userMain/CategoriesPage.js +++ b/src/pages/userMain/CategoriesPage.js @@ -29,19 +29,22 @@ const categories = Object.keys(categoriesInfo).map(key => categoriesInfo[key].na // ๐ŸŒฟ ์นดํ…Œ๊ณ ๋ฆฌ ๋ฌธ์ž์—ด์—์„œ ์‹ค์ œ foodType๋งŒ ์ถ”์ถœํ•˜๋Š” ํ•จ์ˆ˜ const extractFoodType = (category) => { - const match = category.match(/\(foodType=(.*?)\)/); - return match ? match[1] : category; + if (category && typeof category === 'string') { + const match = category.match(/\(foodType=(.*?)\)/); + return match ? match[1] : category; + } + return ''; // category๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋นˆ ๋ฌธ์ž์—ด ๋ฐ˜ํ™˜ }; const CategoriesPage = () => { const { categoryName } = useParams(); const [stores, setStores] = useState([]); - // ์นดํ…Œ๊ณ ๋ฆฌ ์ •๋ณด - const category = categoriesInfo[categoryName]; + // ์นดํ…Œ๊ณ ๋ฆฌ ์ •๋ณด(null์ธ ๊ฒฝ์šฐ ๊ธฐํƒ€๋กœ ๋ถ„๋ฅ˜) + const category = categoriesInfo[categoryName] || { name: '๊ธฐํƒ€', image: salad }; useEffect(() => { - fetch(STORELISTS_URL) + fetch(STORELISTS_URL) .then(response => response.json()) .then(data => { const filteredStores = data.filter(store => extractFoodType(store.category) === category.name); @@ -55,10 +58,9 @@ const CategoriesPage = () => { {/* ์นดํ…Œ๊ณ ๋ฆฌ ๋ถ„๋ฅ˜(ํ—ค๋”) */}

{category.name}

- {category.name} - + {category.name}
- + {/* ์นดํ…Œ๊ณ ๋ฆฌ ๋ฒ„ํŠผ */} {}} /> From 65d151ec3775602afce2905d1928af1abefd52fa Mon Sep 17 00:00:00 2001 From: hyerin11 Date: Tue, 6 Aug 2024 12:02:38 +0900 Subject: [PATCH 2/8] =?UTF-8?q?#=20=EC=B0=9C=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/mainPage/CategoryList.js | 25 ++- .../mainPage/CategoryList.module.scss | 152 +++++++++--------- 2 files changed, 101 insertions(+), 76 deletions(-) diff --git a/src/components/mainPage/CategoryList.js b/src/components/mainPage/CategoryList.js index e107063f..29cfcbf6 100644 --- a/src/components/mainPage/CategoryList.js +++ b/src/components/mainPage/CategoryList.js @@ -1,16 +1,25 @@ -import React from 'react'; +import React, { useState } from 'react'; import styles from './CategoryList.module.scss'; import { useModal } from '../../pages/common/ModalProvider'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faWonSign, faBoxOpen } from "@fortawesome/free-solid-svg-icons"; +import { faWonSign, faBoxOpen, faHeart as faHeartSolid } from "@fortawesome/free-solid-svg-icons"; +import { faHeart as faHeartRegular } from "@fortawesome/free-regular-svg-icons"; const CategoryList = ({ stores }) => { const { openModal } = useModal(); + const [favorites, setFavorites] = useState({}); // ์ฐœ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•  ๊ฐ์ฒด const handleClick = (store) => { openModal('productDetail', { productDetail: store }); }; + const handleFavoriteClick = (storeId) => { + setFavorites(prevFavorites => ({ + ...prevFavorites, + [storeId]: !prevFavorites[storeId] + })); + }; + return (

์šฐ๋ฆฌ ๋™๋„ค ๊ฐ€๊ฒŒ ๋ฆฌ์ŠคํŠธ

@@ -21,6 +30,18 @@ const CategoryList = ({ stores }) => { className={`${styles.categoryItem} ${store.productCnt === 1 ? styles['low-stock'] : ''}`} onClick={() => handleClick(store)} > +
{ + e.stopPropagation(); + handleFavoriteClick(store.storeId); + }} + > + +
{store.storeName} {store.productCnt === 1 &&
SOLD OUT
}

{store.storeName}

diff --git a/src/components/mainPage/CategoryList.module.scss b/src/components/mainPage/CategoryList.module.scss index 82d5c155..0d704d1a 100644 --- a/src/components/mainPage/CategoryList.module.scss +++ b/src/components/mainPage/CategoryList.module.scss @@ -30,89 +30,92 @@ text-align: center; position: relative; height: 250px; -} - -.categoryImage { - width: 100%; - height: 180px; - object-fit: cover; - display: block; - border-radius: 10px; - border: 1px solid #cecece; -} - -.categoryItem p { - height: 15%; - display: flex; - align-items: center; - padding: 20px 0 10px 10px; - position: absolute; - bottom: 40px; - left: 0; - right: 0; - font-size: 20px; -} - -.storePrice { - font-size: 15px; - position: absolute; - bottom: 20px; - left: 10px; -} - -.productCnt { - font-size: 15px; - position: absolute; - bottom: 20px; - right: 10px; -} + + // ์ˆ˜๋Ÿ‰ 0์ผ ๋•Œ ํšŒ์ƒ‰์ฒ˜๋ฆฌ + position: relative; + overflow: hidden; + .categoryImage { + width: 100%; + height: 180px; + object-fit: cover; + display: block; + border-radius: 10px; + border: 1px solid #cecece; + transition: opacity 0.3s ease; + } + .overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 72%; + background: rgba(0, 0, 0, 0.2); + border-radius: 15px; + display: flex; + align-items: center; + justify-content: center; + color: #fff; + font-size: 18px; + font-weight: bold; + opacity: 0; + transition: opacity 0.3s ease; + } -// ์ˆ˜๋Ÿ‰ 0์ผ ๋•Œ ํšŒ์ƒ‰์ฒ˜๋ฆฌ + &.low-stock { + .overlay { + opacity: 1; + } -.categoryItem { - position: relative; - overflow: hidden; -} + .categoryImage { + opacity: 0.5; + } + } -.categoryImage { - width: 100%; - height: 180px; - object-fit: cover; - display: block; - border-radius: 10px; - border: 1px solid #cecece; - transition: opacity 0.3s ease; -} + // ์ฐœ ๊ธฐ๋Šฅ ํ•˜ํŠธ ์•„์ด์ฝ˜ + .heartIcon { + font-size: 18px; + color: rgb(255, 71, 114); + position: absolute; + right: 10px; + bottom: 80px; + z-index: 1; + transition: transform 0.3s ease, color 0.3s ease; + + &:hover { + transform: scale(1.2); + color: rgb(255, 0, 100); + } + } -.overlay { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 72%; - background: rgba(0, 0, 0, 0.2); - border-radius: 15px; - display: flex; - align-items: center; - justify-content: center; - color: #fff; - font-size: 18px; - font-weight: bold; - opacity: 0; - transition: opacity 0.3s ease; -} + p { + height: 15%; + display: flex; + align-items: center; + padding: 20px 0 10px 10px; + position: absolute; + bottom: 40px; + left: 0; + right: 0; + font-size: 20px; + } -.categoryItem.low-stock .overlay { - opacity: 1; -} + .storePrice { + font-size: 15px; + position: absolute; + bottom: 20px; + left: 10px; + } -.categoryItem.low-stock .categoryImage { - opacity: 0.5; + .productCnt { + font-size: 15px; + position: absolute; + bottom: 20px; + right: 10px; + } } - @media (max-width: 1200px) { .categoryItem { flex: 1 1 calc(33.333% - 20px); @@ -126,10 +129,11 @@ } @media (max-width: 400px) { - .list{ + .list { margin: 0 20px; width: 90%; } + .categoryItem { flex: 1 1 100%; } From 986ff37d1d7f373a4d61b00c59aa0459c708681e Mon Sep 17 00:00:00 2001 From: hyerin11 Date: Tue, 6 Aug 2024 14:19:25 +0900 Subject: [PATCH 3/8] =?UTF-8?q?#=20slidesToScroll=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0=20=EB=B0=8F=205=EA=B0=9C=EC=94=A9=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/mainPage/FoodNav.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/mainPage/FoodNav.js b/src/components/mainPage/FoodNav.js index 241de2ce..9ca609b5 100644 --- a/src/components/mainPage/FoodNav.js +++ b/src/components/mainPage/FoodNav.js @@ -39,10 +39,10 @@ const FoodNav = ({ selectedCategory, stores }) => { const settings = (slidesToShow) => ({ dots: true, infinite: true, - speed: 500, + speed: 900, slidesToShow: slidesToShow, - slidesToScroll: 5, - centerMode: true, + slidesToScroll: slidesToShow, + centerMode: false, centerPadding: '0', arrows: true, responsive: [ @@ -50,7 +50,9 @@ const FoodNav = ({ selectedCategory, stores }) => { breakpoint: 400, settings: { dots: false, - slidesToShow: 2, + slidesToShow: 2, + slidesToScroll: 1, + centerMode: true, centerPadding: '10%', }, }, @@ -102,7 +104,7 @@ const FoodNav = ({ selectedCategory, stores }) => { {/* ์ถ”์ฒœ ๊ฐ€๊ฒŒ ๋ฆฌ์ŠคํŠธ(๋žœ๋ค) */}

์ด์›ƒ๋“ค์˜ ์ถ”์ฒœ ๊ฐ€๊ฒŒ

- + {randomStores.map((store, index) => (
Date: Tue, 6 Aug 2024 16:25:50 +0900 Subject: [PATCH 4/8] =?UTF-8?q?#=20dot=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/mainPage/FoodNav.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/mainPage/FoodNav.js b/src/components/mainPage/FoodNav.js index 9ca609b5..21dbb30f 100644 --- a/src/components/mainPage/FoodNav.js +++ b/src/components/mainPage/FoodNav.js @@ -37,7 +37,7 @@ const FoodNav = ({ selectedCategory, stores }) => { }; const settings = (slidesToShow) => ({ - dots: true, + dots: false, infinite: true, speed: 900, slidesToShow: slidesToShow, From 7201af9cace75c17517d5404c960b07c45d90df8 Mon Sep 17 00:00:00 2001 From: hyerin11 Date: Thu, 8 Aug 2024 11:24:40 +0900 Subject: [PATCH 5/8] =?UTF-8?q?#=20customerId=20=EC=9E=84=EC=8B=9C?= =?UTF-8?q?=EB=A1=9C=20=EC=B0=9C=20=EB=B2=84=ED=8A=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 29 ++++++++++ package.json | 1 + src/components/mainPage/CategoryList.js | 70 ++++++++++++++++++++++--- 3 files changed, 93 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index ec67f89e..c79fc2a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "axios": "^1.7.3", "bootstrap": "^5.3.3", "eslint-config-react-app": "^7.0.1", "eslint-plugin-jsx-a11y": "^6.9.0", @@ -5391,6 +5392,29 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.3.tgz", + "integrity": "sha512-Ar7ND9pU99eJ9GpoGQKhKf58GpUOgnzuaB7ueNQ5BMi0p+LZ5oaEnfF999fAArcTIBwXTCHAmGcHOZJaWPq9Nw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/axobject-query": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", @@ -14487,6 +14511,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", diff --git a/package.json b/package.json index f3ab8e06..00b2906d 100755 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "axios": "^1.7.3", "bootstrap": "^5.3.3", "eslint-config-react-app": "^7.0.1", "eslint-plugin-jsx-a11y": "^6.9.0", diff --git a/src/components/mainPage/CategoryList.js b/src/components/mainPage/CategoryList.js index 29cfcbf6..2ba6db82 100644 --- a/src/components/mainPage/CategoryList.js +++ b/src/components/mainPage/CategoryList.js @@ -1,25 +1,81 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import styles from './CategoryList.module.scss'; import { useModal } from '../../pages/common/ModalProvider'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faWonSign, faBoxOpen, faHeart as faHeartSolid } from "@fortawesome/free-solid-svg-icons"; import { faHeart as faHeartRegular } from "@fortawesome/free-regular-svg-icons"; +// ํ•˜ํŠธ ์ƒํƒœ๋ฅผ ํ† ๊ธ€ํ•˜๊ณ  ์„œ๋ฒ„์— ์ €์žฅํ•˜๋Š” ํ•จ์ˆ˜ +const toggleFavorite = async (storeId, customerId) => { + try { + const response = await fetch(`http://localhost:8083/api/favorites/${storeId}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ customerId }), + }); + + if (!response.ok) { + throw new Error('Network response was not ok'); + } + + const data = await response.json(); + console.log('Favorite toggled successfully:', data); + } catch (error) { + console.error('Error toggling favorite:', error); + } +}; + +const fetchFavorites = async (customerId, setFavorites) => { + try { + const response = await fetch(`http://localhost:8083/api/favorites/user/${customerId}`); + if (!response.ok) { + throw new Error('Network response was not ok'); + } + const data = await response.json(); + const favorites = data.reduce((acc, store) => { + acc[store.storeId] = true; + return acc; + }, {}); + setFavorites(favorites); + } catch (error) { + console.error('Error fetching favorites:', error); + } +}; + const CategoryList = ({ stores }) => { const { openModal } = useModal(); - const [favorites, setFavorites] = useState({}); // ์ฐœ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•  ๊ฐ์ฒด + const [favorites, setFavorites] = useState({}); + + // ์‹ค์ œ customerId์™€ storeId ์„ค์ • + const customerId = 'test@gmail.com'; // ์‹ค์ œ customerId + const storeId = 'thdghtjd115@naver.com'; // ์‹ค์ œ storeId const handleClick = (store) => { openModal('productDetail', { productDetail: store }); }; - const handleFavoriteClick = (storeId) => { - setFavorites(prevFavorites => ({ - ...prevFavorites, - [storeId]: !prevFavorites[storeId] - })); + const handleFavoriteClick = async (storeId) => { + try { + await toggleFavorite(storeId, customerId); + + // ์ฐœ ์ƒํƒœ๋ฅผ ํ† ๊ธ€ + setFavorites(prevFavorites => ({ + ...prevFavorites, + [storeId]: !prevFavorites[storeId] + })); + } catch (error) { + console.error('Error toggling favorite:', error); + } }; + useEffect(() => { + if (customerId) { + fetchFavorites(customerId, setFavorites); + } + }, [customerId]); + return (

์šฐ๋ฆฌ ๋™๋„ค ๊ฐ€๊ฒŒ ๋ฆฌ์ŠคํŠธ

From 7d004e5b0b864efbb986b456fdaae4a8c70fdd5f Mon Sep 17 00:00:00 2001 From: hyerin11 Date: Thu, 8 Aug 2024 15:12:08 +0900 Subject: [PATCH 6/8] =?UTF-8?q?#=20host-config=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=EB=B0=8F=20JSON=20=ED=8C=8C=EC=8B=B1=20=ED=99=95=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/mainPage/CategoryList.js | 45 ++++++++++++++++--------- src/config/host-config.js | 4 ++- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/components/mainPage/CategoryList.js b/src/components/mainPage/CategoryList.js index 2ba6db82..a7a92f64 100644 --- a/src/components/mainPage/CategoryList.js +++ b/src/components/mainPage/CategoryList.js @@ -4,11 +4,12 @@ import { useModal } from '../../pages/common/ModalProvider'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faWonSign, faBoxOpen, faHeart as faHeartSolid } from "@fortawesome/free-solid-svg-icons"; import { faHeart as faHeartRegular } from "@fortawesome/free-regular-svg-icons"; +import { FAVORITESTORE_URL } from '../../config/host-config'; // ํ•˜ํŠธ ์ƒํƒœ๋ฅผ ํ† ๊ธ€ํ•˜๊ณ  ์„œ๋ฒ„์— ์ €์žฅํ•˜๋Š” ํ•จ์ˆ˜ const toggleFavorite = async (storeId, customerId) => { try { - const response = await fetch(`http://localhost:8083/api/favorites/${storeId}`, { + const response = await fetch(`${FAVORITESTORE_URL}/${storeId}`, { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -16,29 +17,42 @@ const toggleFavorite = async (storeId, customerId) => { body: JSON.stringify({ customerId }), }); - if (!response.ok) { - throw new Error('Network response was not ok'); + // ์‘๋‹ต์˜ Content-Type์„ ํ™•์ธํ•˜์—ฌ JSON์œผ๋กœ ํŒŒ์‹ฑํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธ + const contentType = response.headers.get('Content-Type'); + if (contentType && contentType.includes('application/json')) { + const data = await response.json(); + console.log('Favorite toggled successfully:', data); + } else { + // JSON์ด ์•„๋‹Œ ์‘๋‹ต์„ ์ฒ˜๋ฆฌ + const text = await response.text(); + console.error('Unexpected response format:', text); } - const data = await response.json(); - console.log('Favorite toggled successfully:', data); } catch (error) { console.error('Error toggling favorite:', error); } }; +// ์‚ฌ์šฉ์ž์˜ ๋ชจ๋“  ์ฐœ ์ƒํƒœ ์กฐํšŒ const fetchFavorites = async (customerId, setFavorites) => { try { - const response = await fetch(`http://localhost:8083/api/favorites/user/${customerId}`); - if (!response.ok) { - throw new Error('Network response was not ok'); + const response = await fetch(`${FAVORITESTORE_URL}/${customerId}`); + + // ์‘๋‹ต์˜ Content-Type์„ ํ™•์ธํ•˜์—ฌ JSON์œผ๋กœ ํŒŒ์‹ฑํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธ + const contentType = response.headers.get('Content-Type'); + if (contentType && contentType.includes('application/json')) { + const data = await response.json(); + const favorites = data.reduce((acc, store) => { + acc[store.storeId] = true; + return acc; + }, {}); + setFavorites(favorites); + } else { + // JSON์ด ์•„๋‹Œ ์‘๋‹ต์„ ์ฒ˜๋ฆฌ + const text = await response.text(); + console.error('Unexpected response format:', text); } - const data = await response.json(); - const favorites = data.reduce((acc, store) => { - acc[store.storeId] = true; - return acc; - }, {}); - setFavorites(favorites); + } catch (error) { console.error('Error fetching favorites:', error); } @@ -49,8 +63,7 @@ const CategoryList = ({ stores }) => { const [favorites, setFavorites] = useState({}); // ์‹ค์ œ customerId์™€ storeId ์„ค์ • - const customerId = 'test@gmail.com'; // ์‹ค์ œ customerId - const storeId = 'thdghtjd115@naver.com'; // ์‹ค์ œ storeId + const customerId = 'test@gmail.com'; const handleClick = (store) => { openModal('productDetail', { productDetail: store }); diff --git a/src/config/host-config.js b/src/config/host-config.js index 1062ae78..b20f0d94 100755 --- a/src/config/host-config.js +++ b/src/config/host-config.js @@ -1,10 +1,12 @@ + const STORE = '/store'; const CUSTOMER = '/customer'; const STORELISTS = '/storeLists'; const EMAIL = '/email'; +const FAVORITESTORE = '/api/favorites'; export const STORE_URL = STORE; export const CUSTOMER_URL = CUSTOMER; export const STORELISTS_URL = STORELISTS; - export const EMAIL_URL = EMAIL; +export const FAVORITESTORE_URL = FAVORITESTORE; From aa1e6142da75e53c1d1b29706684d8e7371cd5a0 Mon Sep 17 00:00:00 2001 From: hyerin11 Date: Thu, 8 Aug 2024 16:13:08 +0900 Subject: [PATCH 7/8] =?UTF-8?q?#=20refreshToken=20=EC=A0=81=EC=9A=A9=20?= =?UTF-8?q?=EC=98=88=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/mainPage/CategoryList.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/components/mainPage/CategoryList.js b/src/components/mainPage/CategoryList.js index a7a92f64..4c463f63 100644 --- a/src/components/mainPage/CategoryList.js +++ b/src/components/mainPage/CategoryList.js @@ -13,6 +13,8 @@ const toggleFavorite = async (storeId, customerId) => { method: 'POST', headers: { 'Content-Type': 'application/json', + // 'Authorization' : 'Bearer ' + token, + // 'refreshToken' : refreshToken }, body: JSON.stringify({ customerId }), }); @@ -21,15 +23,15 @@ const toggleFavorite = async (storeId, customerId) => { const contentType = response.headers.get('Content-Type'); if (contentType && contentType.includes('application/json')) { const data = await response.json(); - console.log('Favorite toggled successfully:', data); + //console.log('Favorite toggled successfully!', data); } else { // JSON์ด ์•„๋‹Œ ์‘๋‹ต์„ ์ฒ˜๋ฆฌ const text = await response.text(); - console.error('Unexpected response format:', text); + console.error('โš ๏ธUnexpected response format:', text); } } catch (error) { - console.error('Error toggling favorite:', error); + console.error('โš ๏ธError toggling:', error); } }; @@ -50,19 +52,23 @@ const fetchFavorites = async (customerId, setFavorites) => { } else { // JSON์ด ์•„๋‹Œ ์‘๋‹ต์„ ์ฒ˜๋ฆฌ const text = await response.text(); - console.error('Unexpected response format:', text); + console.error('โš ๏ธUnexpected response format:', text); } } catch (error) { - console.error('Error fetching favorites:', error); + console.error('โš ๏ธError fetching:', error); } }; + + + + const CategoryList = ({ stores }) => { const { openModal } = useModal(); const [favorites, setFavorites] = useState({}); - // ์‹ค์ œ customerId์™€ storeId ์„ค์ • + // customerId ๋”๋ฏธ๊ฐ’ const customerId = 'test@gmail.com'; const handleClick = (store) => { @@ -79,7 +85,7 @@ const CategoryList = ({ stores }) => { [storeId]: !prevFavorites[storeId] })); } catch (error) { - console.error('Error toggling favorite:', error); + console.error('โš ๏ธError toggling:', error); } }; From ceef195c1f1c2e6cda49ba1ca558871f829ce920 Mon Sep 17 00:00:00 2001 From: hyerin11 Date: Thu, 8 Aug 2024 17:53:07 +0900 Subject: [PATCH 8/8] =?UTF-8?q?#=20=EC=B0=9C=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EB=AA=A8=EB=93=A0=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/mainPage/BestStoreList.js | 190 +++++++++++++----- src/components/mainPage/CategoryList.js | 3 +- .../mainPage/CategoryList.module.scss | 39 ++-- src/components/mainPage/FoodNav.js | 118 ++++++++++- src/components/mainPage/FoodNav.module.scss | 29 +++ 5 files changed, 302 insertions(+), 77 deletions(-) diff --git a/src/components/mainPage/BestStoreList.js b/src/components/mainPage/BestStoreList.js index d322b4a8..36fded73 100644 --- a/src/components/mainPage/BestStoreList.js +++ b/src/components/mainPage/BestStoreList.js @@ -1,63 +1,145 @@ -import React from 'react'; +import React, { useState, useEffect } from 'react'; import Slider from 'react-slick'; import 'slick-carousel/slick/slick.css'; import 'slick-carousel/slick/slick-theme.css'; -import styles from './FoodNav.module.scss'; - +import styles from './FoodNav.module.scss'; // ์ˆ˜์ •๋œ SCSS ํŒŒ์ผ ๊ฒฝ๋กœ import { useModal } from '../../pages/common/ModalProvider'; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faWonSign, faBoxOpen, faHeart as faHeartSolid } from "@fortawesome/free-solid-svg-icons"; +import { faHeart as faHeartRegular } from "@fortawesome/free-regular-svg-icons"; +import { FAVORITESTORE_URL } from '../../config/host-config'; + +// ํ•˜ํŠธ ์ƒํƒœ๋ฅผ ํ† ๊ธ€ํ•˜๊ณ  ์„œ๋ฒ„์— ์ €์žฅํ•˜๋Š” ํ•จ์ˆ˜ +const toggleFavorite = async (storeId, customerId) => { + try { + const response = await fetch(`${FAVORITESTORE_URL}/${storeId}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ customerId }), + }); + + const contentType = response.headers.get('Content-Type'); + if (contentType && contentType.includes('application/json')) { + const data = await response.json(); + } else { + const text = await response.text(); + console.error('โš ๏ธUnexpected response format:', text); + } + + } catch (error) { + console.error('โš ๏ธError toggling:', error); + } +}; + +// ์‚ฌ์šฉ์ž์˜ ๋ชจ๋“  ์ฐœ ์ƒํƒœ ์กฐํšŒ +const fetchFavorites = async (customerId, setFavorites) => { + try { + const response = await fetch(`${FAVORITESTORE_URL}/${customerId}`); + + const contentType = response.headers.get('Content-Type'); + if (contentType && contentType.includes('application/json')) { + const data = await response.json(); + const favorites = data.reduce((acc, store) => { + acc[store.storeId] = true; + return acc; + }, {}); + setFavorites(favorites); + } else { + const text = await response.text(); + console.error('โš ๏ธUnexpected response format:', text); + } + + } catch (error) { + console.error('โš ๏ธError fetching:', error); + } +}; const BestStoreList = ({ stores = [] }) => { - const { openModal } = useModal(); - - const settings = { - slidesToShow: 5, - slidesToScroll: 5, - infinite: true, - arrows: true, - dots: true, - centerMode: true, - centerPadding: '0', - responsive: [ - { - breakpoint: 400, - settings: { - dots: false, - slidesToShow: 2, - centerPadding: '10%', - // centerMode: false, - }, - }, - ], - }; - - const handleClick = (store) => { - openModal('productDetail', { productDetail: store }); - }; - - return ( -
-

์ถ”์ฒœ ๊ฐ€๊ฒŒ

- - {stores.length === 0 ? ( -
No stores available
- ) : ( - stores.map((store, index) => ( -
handleClick(store)} - > - {store.storeName} - {store.productCnt === 1 &&
SOLD OUT
} -

{store.storeName}

- {store.price} - ์ˆ˜๋Ÿ‰: {store.productCnt} -
- )) - )} -
-
- ); + const { openModal } = useModal(); + const [favorites, setFavorites] = useState({}); + + // customerId ๋”๋ฏธ๊ฐ’ + const customerId = 'test@gmail.com'; + + useEffect(() => { + if (customerId) { + fetchFavorites(customerId, setFavorites); + } + }, [customerId]); + + const handleClick = (store) => { + openModal('productDetail', { productDetail: store }); + }; + + const handleFavoriteClick = async (storeId) => { + try { + await toggleFavorite(storeId, customerId); + + setFavorites(prevFavorites => ({ + ...prevFavorites, + [storeId]: !prevFavorites[storeId] + })); + } catch (error) { + console.error('โš ๏ธError toggling:', error); + } + }; + + const settings = { + slidesToShow: 5, + slidesToScroll: 5, + infinite: true, + arrows: true, + dots: true, + centerMode: true, + centerPadding: '0', + responsive: [ + { + breakpoint: 400, + settings: { + dots: false, + slidesToShow: 2, + centerPadding: '10%', + }, + }, + ], + }; + + return ( +
+

์ถ”์ฒœ ๊ฐ€๊ฒŒ

+ + {stores.length === 0 ? ( +
No stores available
+ ) : ( + stores.map((store, index) => ( +
+
{ + e.stopPropagation(); + handleFavoriteClick(store.storeId); + }} + > + +
+ {store.storeName} + {store.productCnt === 1 &&
SOLD OUT
} +

{store.storeName}

+ {store.price} + ์ˆ˜๋Ÿ‰: {store.productCnt} +
+ )) + )} +
+
+ ); }; export default BestStoreList; diff --git a/src/components/mainPage/CategoryList.js b/src/components/mainPage/CategoryList.js index 4c463f63..8fa009d0 100644 --- a/src/components/mainPage/CategoryList.js +++ b/src/components/mainPage/CategoryList.js @@ -106,7 +106,7 @@ const CategoryList = ({ stores }) => { onClick={() => handleClick(store)} >
{ e.stopPropagation(); handleFavoriteClick(store.storeId); @@ -114,7 +114,6 @@ const CategoryList = ({ stores }) => { >
{store.storeName} diff --git a/src/components/mainPage/CategoryList.module.scss b/src/components/mainPage/CategoryList.module.scss index 0d704d1a..cfb568e6 100644 --- a/src/components/mainPage/CategoryList.module.scss +++ b/src/components/mainPage/CategoryList.module.scss @@ -73,21 +73,34 @@ } } - // ์ฐœ ๊ธฐ๋Šฅ ํ•˜ํŠธ ์•„์ด์ฝ˜ - .heartIcon { - font-size: 18px; - color: rgb(255, 71, 114); - position: absolute; - right: 10px; - bottom: 80px; - z-index: 1; - transition: transform 0.3s ease, color 0.3s ease; +// ์ฐœ ๊ธฐ๋Šฅ ํ•˜ํŠธ ์•„์ด์ฝ˜ +.heartIcon { + font-size: 18px; + color: rgb(152, 152, 152); + position: absolute; + right: 10px; + bottom: 80px; + z-index: 1; + transition: transform 0.3s ease, color 0.3s ease; + + // ๋งˆ์šฐ์Šค๋ฅผ ์˜ฌ๋ ธ์„ ๋•Œ + &:hover { + transform: scale(1.2); + color: rgb(255, 0, 100); + } - &:hover { - transform: scale(1.2); - color: rgb(255, 0, 100); - } + // ํด๋ฆญํ–ˆ์„ ๋•Œ + &.favorited { + color: rgb(255, 71, 114); } +} + +// ํด๋ฆญ๋œ ์ƒํƒœ์—์„œ ๋งˆ์šฐ์Šค ์˜ฌ๋ ธ์„ ๋•Œ +.heartIcon.favorited:hover { + transform: scale(1.1); + color: rgb(255, 0, 100); +} + p { height: 15%; diff --git a/src/components/mainPage/FoodNav.js b/src/components/mainPage/FoodNav.js index 21dbb30f..f3dd7d93 100644 --- a/src/components/mainPage/FoodNav.js +++ b/src/components/mainPage/FoodNav.js @@ -5,6 +5,10 @@ import styles from "./FoodNav.module.scss"; import "slick-carousel/slick/slick.css"; import "slick-carousel/slick/slick-theme.css"; import './slick-theme.css'; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faHeart as faHeartSolid } from "@fortawesome/free-solid-svg-icons"; +import { faHeart as faHeartRegular } from "@fortawesome/free-regular-svg-icons"; +import { FAVORITESTORE_URL } from '../../config/host-config'; // ๐ŸŒฟ ๋žœ๋ค ๊ฐ€๊ฒŒ ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ const getRandomStores = (stores, count) => { @@ -14,28 +18,93 @@ const getRandomStores = (stores, count) => { // ๐ŸŒฟ ์นดํ…Œ๊ณ ๋ฆฌ ๋ฌธ์ž์—ด์—์„œ ์‹ค์ œ foodType๋งŒ ์ถ”์ถœํ•˜๋Š” ํ•จ์ˆ˜ const extractFoodType = (category) => { - // category๊ฐ€ ์œ ํšจํ•œ ๋ฌธ์ž์—ด์ธ์ง€ ํ™•์ธ - if (category && typeof category === 'string') { - // 'foodType=' ์ดํ›„์˜ ๊ฐ’ ์ถ”์ถœ + if (category && typeof category === 'string') { const match = category.match(/\(foodType=(.*?)\)/); - return match ? match[1] : category; + return match ? match[1] : category; + } + return ''; +}; + +// ํ•˜ํŠธ ์ƒํƒœ๋ฅผ ํ† ๊ธ€ํ•˜๊ณ  ์„œ๋ฒ„์— ์ €์žฅํ•˜๋Š” ํ•จ์ˆ˜ +const toggleFavorite = async (storeId, customerId) => { + try { + const response = await fetch(`${FAVORITESTORE_URL}/${storeId}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ customerId }), + }); + + const contentType = response.headers.get('Content-Type'); + if (contentType && contentType.includes('application/json')) { + const data = await response.json(); + } else { + const text = await response.text(); + console.error('โš ๏ธUnexpected response format:', text); } - return ''; // category๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋นˆ ๋ฌธ์ž์—ด ๋ฐ˜ํ™˜ + } catch (error) { + console.error('โš ๏ธError toggling:', error); + } +}; + +// ์‚ฌ์šฉ์ž์˜ ๋ชจ๋“  ์ฐœ ์ƒํƒœ ์กฐํšŒ +const fetchFavorites = async (customerId, setFavorites) => { + try { + const response = await fetch(`${FAVORITESTORE_URL}/${customerId}`); + + const contentType = response.headers.get('Content-Type'); + if (contentType && contentType.includes('application/json')) { + const data = await response.json(); + const favorites = data.reduce((acc, store) => { + acc[store.storeId] = true; + return acc; + }, {}); + setFavorites(favorites); + } else { + const text = await response.text(); + console.error('โš ๏ธUnexpected response format:', text); + } + } catch (error) { + console.error('โš ๏ธError fetching:', error); + } }; const FoodNav = ({ selectedCategory, stores }) => { const [randomStores, setRandomStores] = useState([]); + const [favorites, setFavorites] = useState({}); const { openModal } = useModal(); + // customerId ๋”๋ฏธ๊ฐ’ + const customerId = 'test@gmail.com'; + useEffect(() => { - // ๋žœ๋คํ•œ ๊ฐ€๊ฒŒ ๋ชฉ๋ก์„ ์„ ํƒํ•˜์—ฌ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธ - setRandomStores(getRandomStores(stores, 5)); + setRandomStores(getRandomStores(stores, 5)); }, [stores]); + useEffect(() => { + if (customerId) { + fetchFavorites(customerId, setFavorites); + } + }, [customerId]); + const handleClick = (store) => { openModal('productDetail', { productDetail: store }); }; + const handleFavoriteClick = async (storeId) => { + try { + await toggleFavorite(storeId, customerId); + + setFavorites(prevFavorites => ({ + ...prevFavorites, + [storeId]: !prevFavorites[storeId] + })); + } catch (error) { + console.error('โš ๏ธError toggling:', error); + } + }; + const settings = (slidesToShow) => ({ dots: false, infinite: true, @@ -51,7 +120,7 @@ const FoodNav = ({ selectedCategory, stores }) => { settings: { dots: false, slidesToShow: 2, - slidesToScroll: 1, + slidesToScroll: 1, centerMode: true, centerPadding: '10%', }, @@ -71,6 +140,17 @@ const FoodNav = ({ selectedCategory, stores }) => { onClick={() => handleClick(store)} className={`${styles.storeItem} ${store.productCnt === 1 ? styles['low-stock'] : ''}`} > +
{ + e.stopPropagation(); + handleFavoriteClick(store.storeId); + }} + > + +
{store.storeName} {store.productCnt === 1 &&
SOLD OUT
}

{store.storeName}

@@ -91,6 +171,17 @@ const FoodNav = ({ selectedCategory, stores }) => { onClick={() => handleClick(store)} className={`${styles.storeItem} ${store.productCnt === 1 ? styles['low-stock'] : ''}`} > +
{ + e.stopPropagation(); + handleFavoriteClick(store.storeId); + }} + > + +
{store.storeName} {store.productCnt === 1 &&
SOLD OUT
}

{store.storeName}

@@ -111,6 +202,17 @@ const FoodNav = ({ selectedCategory, stores }) => { onClick={() => handleClick(store)} className={`${styles.storeItem} ${store.productCnt === 1 ? styles['low-stock'] : ''}`} > +
{ + e.stopPropagation(); + handleFavoriteClick(store.storeId); + }} + > + +
{store.storeName} {extractFoodType(store.category)}

{store.storeName}

diff --git a/src/components/mainPage/FoodNav.module.scss b/src/components/mainPage/FoodNav.module.scss index e48301c6..45f8359b 100644 --- a/src/components/mainPage/FoodNav.module.scss +++ b/src/components/mainPage/FoodNav.module.scss @@ -137,6 +137,35 @@ } +// ์ฐœ ํ•˜ํŠธ ๊ธฐ๋Šฅ +.heartIcon { + font-size: 18px; + color: rgb(152, 152, 152); // ๊ธฐ๋ณธ ํšŒ์ƒ‰ + position: absolute; + right: 20px; + bottom: 70px; + z-index: 1; + transition: transform 0.3s ease, color 0.3s ease; + + // ๋งˆ์šฐ์Šค๋ฅผ ์˜ฌ๋ ธ์„ ๋•Œ + &:hover { + transform: scale(1.2); + color: rgb(255, 0, 100); // ํ•‘ํฌ์ƒ‰ + } + + // ํด๋ฆญํ–ˆ์„ ๋•Œ + &.favorited { + color: rgb(255, 71, 114); // ๋นจ๊ฐ„์ƒ‰ + } +} + +// ํ•˜ํŠธ ์•„์ด์ฝ˜์ด ํด๋ฆญ๋œ ์ƒํƒœ์—์„œ ํ˜ธ๋ฒ„ํ•  ๋•Œ ์Šคํƒ€์ผ ์ ์šฉ +.heartIcon.favorited:hover { + transform: scale(1.1); + color: rgb(255, 0, 100); // ํ•‘ํฌ์ƒ‰ +} + + @media (max-width: 400px) { .list{