From 44f4b5c3a0e054b2dadc2416fc6cad9f0e7641fc Mon Sep 17 00:00:00 2001 From: Yeryeong Kang Date: Sat, 27 Jun 2026 04:20:39 +0900 Subject: [PATCH 01/14] =?UTF-8?q?feat:=20RestaurantContext,=20ModalContext?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/context/ModalContext.jsx | 56 +++++++++++++++++++++++++++++++ src/context/RestaurantContext.jsx | 40 ++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 src/context/ModalContext.jsx create mode 100644 src/context/RestaurantContext.jsx diff --git a/src/context/ModalContext.jsx b/src/context/ModalContext.jsx new file mode 100644 index 0000000..cd5e547 --- /dev/null +++ b/src/context/ModalContext.jsx @@ -0,0 +1,56 @@ +/* eslint-disable react-refresh/only-export-components */ +import { createContext, useContext, useState } from "react"; +import { useRestaurantContext } from "./RestaurantContext"; + +const ModalContext = createContext(); + +export function ModalProvider({ children }) { + const { registerRestaurant } = useRestaurantContext(); + const [clickedRestaurant, setClickedRestaurant] = useState(null); + const [isAddModalOpen, setIsAddModalOpen] = useState(false); + + const handleRestaurantClick = (restaurant) => { + setClickedRestaurant(restaurant); + }; + + const handleDetailModalClose = () => { + setClickedRestaurant(null); + }; + + const handleAddModalOpen = () => { + setIsAddModalOpen(true); + }; + + const handleAddModalClose = () => { + setIsAddModalOpen(false); + }; + + const handleFormSubmit = async (newRestaurant) => { + try { + await registerRestaurant(newRestaurant); + setIsAddModalOpen(false); + } catch { + alert("음식점 추가에 실패했습니다. 다시 시도해주세요."); + } + }; + + return ( + + {children} + + ); +} + +export function useModalContext() { + return useContext(ModalContext); +} diff --git a/src/context/RestaurantContext.jsx b/src/context/RestaurantContext.jsx new file mode 100644 index 0000000..10b583c --- /dev/null +++ b/src/context/RestaurantContext.jsx @@ -0,0 +1,40 @@ +/* eslint-disable react-refresh/only-export-components */ +import { createContext, useContext, useState } from "react"; +import { useRestaurants } from "../hooks/useRestaurants"; +import { ALL_CATEGORY } from "../constants/categories"; + +const RestaurantContext = createContext(); + +export function RestaurantProvider({ children }) { + const { newRestaurants, registerRestaurant, error, isLoading } = + useRestaurants(); + const [category, setCategory] = useState(ALL_CATEGORY); + + const filteredRestaurants = + category === ALL_CATEGORY + ? newRestaurants + : newRestaurants.filter((r) => r.category === category); + + const handleSelectChange = (e) => { + setCategory(e.target.value); + }; + + return ( + + {children} + + ); +} + +export function useRestaurantContext() { + return useContext(RestaurantContext); +} From 169f41ccff4091cd5de2ac8aea689d2a791f565e Mon Sep 17 00:00:00 2001 From: Yeryeong Kang Date: Sat, 27 Jun 2026 04:20:50 +0900 Subject: [PATCH 02/14] =?UTF-8?q?feat:=20App=EC=9D=84=20Provider=EB=A1=9C?= =?UTF-8?q?=20=EA=B0=90=EC=8B=B8=EA=B3=A0=20AppContent=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 86 ++++------------------------------- src/components/AppContent.jsx | 28 ++++++++++++ 2 files changed, 36 insertions(+), 78 deletions(-) create mode 100644 src/components/AppContent.jsx diff --git a/src/App.jsx b/src/App.jsx index 5c5d6c0..0eba73d 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,85 +1,15 @@ -import { ALL_CATEGORY } from "./constants/categories"; -import { useState } from "react"; import "./App.css"; -import Header from "./components/Header/Header"; -import CategoryFilter from "./components/CategoryFilter/CategoryFilter"; -import RestaurantList from "./components/RestaurantList/RestaurantList"; -import RestaurantDetailModal from "./components/Modal/RestaurantDetailModal"; -import AddRestaurantModal from "./components/Modal/AddRestaurantModal"; -import { useRestaurants } from "./hooks/useRestaurants"; +import { RestaurantProvider } from "./context/RestaurantContext"; +import { ModalProvider } from "./context/ModalContext"; +import AppContent from "./components/AppContent"; function App() { - const [category, setCategory] = useState(ALL_CATEGORY); - const [clickedRestaurant, setClickedRestaurant] = useState(null); - const [isAddModalOpen, setIsAddModalOpen] = useState(false); - - const { newRestaurants, registerRestaurant, error, isLoading } = - useRestaurants(); - - const handleFormSubmit = async (newRestaurant) => { - try { - await registerRestaurant(newRestaurant); - setIsAddModalOpen(false); - } catch { - alert("음식점 추가에 실패했습니다. 다시 시도해주세요."); - } - }; - - const filteredRestaurants = - category === ALL_CATEGORY - ? newRestaurants - : newRestaurants.filter((restaurant) => restaurant.category === category); - - const handleSelectChange = (e) => { - setCategory(e.target.value); - }; - - const handleRestaurantClick = (restaurant) => { - setClickedRestaurant(restaurant); - }; - - const handleDetailModalClose = () => { - setClickedRestaurant(null); - }; - - const handleAddModalOpen = () => { - setIsAddModalOpen(true); - }; - - const handleAddModalClose = () => { - setIsAddModalOpen(false); - }; - return ( - <> -
-
- {isLoading &&

로딩중입니다.

} - {error &&

{error}

} - - -
- - + + + + + ); } diff --git a/src/components/AppContent.jsx b/src/components/AppContent.jsx new file mode 100644 index 0000000..8c485fb --- /dev/null +++ b/src/components/AppContent.jsx @@ -0,0 +1,28 @@ +import Header from "./Header/Header"; +import CategoryFilter from "./CategoryFilter/CategoryFilter"; +import RestaurantList from "./RestaurantList/RestaurantList"; +import RestaurantDetailModal from "./Modal/RestaurantDetailModal"; +import AddRestaurantModal from "./Modal/AddRestaurantModal"; +import { useRestaurantContext } from "../context/RestaurantContext"; +import { useModalContext } from "../context/ModalContext"; + +export default function AppContent() { + const { error, isLoading } = useRestaurantContext(); + const { clickedRestaurant, isAddModalOpen, handleAddModalOpen } = useModalContext(); + + return ( + <> +
+
+ {isLoading &&

로딩중입니다.

} + {error &&

{error}

} + + +
+ + + ); +} From b9560efb77eb3897fdb79a4f060fde8a1370048a Mon Sep 17 00:00:00 2001 From: Yeryeong Kang Date: Sat, 27 Jun 2026 04:21:01 +0900 Subject: [PATCH 03/14] =?UTF-8?q?refactor:=20=EA=B0=81=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=EC=97=90=EC=84=9C=20props=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=ED=95=98=EA=B3=A0=20Context=20=EC=A7=81?= =?UTF-8?q?=EC=A0=91=20=EC=86=8C=EB=B9=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/CategoryFilter/CategoryFilter.jsx | 6 ++++-- src/components/Modal/AddRestaurantModal.jsx | 4 +++- src/components/Modal/RestaurantDetailModal.jsx | 4 +++- src/components/RestaurantList/RestaurantList.jsx | 10 +++++++--- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/components/CategoryFilter/CategoryFilter.jsx b/src/components/CategoryFilter/CategoryFilter.jsx index 503d0dd..83616ff 100644 --- a/src/components/CategoryFilter/CategoryFilter.jsx +++ b/src/components/CategoryFilter/CategoryFilter.jsx @@ -1,6 +1,7 @@ import { FILTER_OPTIONS } from "../../constants/categories"; import styled from "styled-components"; import { textBody } from "../../styles/typography"; +import { useRestaurantContext } from "../../context/RestaurantContext"; const FilterContainer = styled.section` display: flex; @@ -19,7 +20,8 @@ const FilterSelect = styled.select` padding: 8px; `; -export default function CategoryFilter({ category, onChangeCategory }) { +export default function CategoryFilter() { + const { category, handleSelectChange } = useRestaurantContext(); return ( {FILTER_OPTIONS.map((option) => (