나만의 맛집 페이지를 구현하는 프로젝트
추가 작업
EATINGMARK-FE
├── src/
│ ├── components/
│ ├── pages/
│ ├── context/
│ ├── api/
│ ├── styles/
│ └── App.jsx
└── public/
📁 UserLocation.jsx
import { Children, createContext, useContext, useEffect, useState } from "react";
import { GetFetchApi } from "./GetFetchApi";
import { sortPlacesByDistance } from "../components/loc";
import { FavoriteFetchApi } from "./FavoriteFetchApi";
export const UserLocation = createContext();
export const UserLocationProvider = ({children}) => {
const {places} = useContext(GetFetchApi)
const {userPlaces} = useContext(FavoriteFetchApi)
const [userLocation, setUserLocation] = useState(null)
const [sortedPlaces, setSortedPlaces] = useState(null); // null로 초기화
const [sortedFavPlaces, setSortedFavPlaces] = useState(null); // null로 초기화
const [isSorted, setIsSorted] = useState(false); // 정렬 상태 확인용
useEffect(() => {
navigator.geolocation.getCurrentPosition((position) => {
setUserLocation({
lon: position.coords.longitude,
lat: position.coords.latitude
})
}, (err) => {
console.error("위치 정보를 가져오는 데 실패했어요!", err)
})
},[])
const sortedClick = () => {
if(!isSorted){
setSortedPlaces(userLocation ? sortPlacesByDistance(places, userLocation.lat, userLocation.lon)
: places)
setSortedFavPlaces(userLocation ? sortPlacesByDistance(userPlaces, userLocation.lat, userLocation.lon)
: userPlaces)
} else {
setSortedPlaces(null);
setSortedFavPlaces(null)
}
setIsSorted((prev) => !prev);
}
return(
<UserLocation.Provider value={{sortedClick, sortedPlaces, isSorted, sortedFavPlaces}}>
{children}
</UserLocation.Provider>
)
}
📁 Main.jsx
import { useContext} from "react"
import { Card } from "../components/Card"
import styles from "../styles/main.module.scss"
import { Favorite } from "./Favorite"
import { GetFetchApi } from "../context/GetFetchApi"
import { UserLocation } from "../context/UserLocation"
export function Main () {
const { places } = useContext(GetFetchApi)
const {sortedClick, sortedPlaces, isSorted} =useContext(UserLocation)
return(
<div className={styles.firdiv}>
<Favorite/>
<div className={styles.secdiv}>
<h1 className={styles.h1}> All Place ... </h1>
<button className={isSorted ? styles.button : styles.button1}
onClick={() => sortedClick()}> {isSorted ? "기본순" : "거리순"}</button>
</div>
<div className={styles.thrdiv}>
{sortedPlaces ?
sortedPlaces.map((place) => <Card key={place.id} place={place}/>)
: places.map((place) => <Card key={place.id} place={place}/>)}
</div>
</div>
)
}
📁 Favorite.jsx
import { useContext } from "react"
import { FavoriteFetchApi } from "../context/FavoriteFetchApi"
import styles from "../styles/favorite.module.scss"
import { Card } from "../components/Card"
import { UserLocation } from "../context/UserLocation"
export function Favorite () {
const {userPlaces} = useContext(FavoriteFetchApi)
const {sortedFavPlaces} = useContext(UserLocation)
const displaySorted = sortedFavPlaces || userPlaces
return(
<>
<div className={styles.container}>
<div className={styles.leftSide}>
<h1 className={styles.h1}>Favorite</h1>
<div className={styles.sidediv}></div>
</div>
<div className={styles.secdiv}>
{displaySorted.length > 0 ? (
displaySorted.map((place) => <Card key={place.id} place={place} />)
) : (
<p>찜한 맛집이 없습니다.</p>
)}
</div>
</div>
</>
)
}
<Route path={"/detail/:placeId"} element={<Detail />}/> ) 중 placeId 값을 useParams 로 받아와서 해당 Id 인 값 화면에 출력📁 Detail.jsx
import { useParams } from "react-router"
import { Card } from "../components/Card"
import { GetFetchApi } from "../context/GetFetchApi"
import { useContext } from "react"
import styles from "../styles/detail.module.scss"
export function Detail () {
const baseURL = import.meta.env.VITE_BASE_URL
const { places } = useContext(GetFetchApi)
const { placeId } = useParams()
const selectedPlace = places.find((el) => String(el.id) === String(placeId));
// console.log(selectedPlace)
return(
<>
<div className={styles.firdiv}>
<h1>{selectedPlace.title}</h1>
<img src={`${baseURL}/${selectedPlace.image.src}`}/>
<div></div>
<p> {selectedPlace.description} </p>
</div>
</>
)
}
📁 Card.jsx
import { useNavigate } from "react-router"
import styles from "../styles/card.module.scss"
import FavoriteBtn from "./FavoriteBtn";
export const Card = ({place}) => {
const navigate = useNavigate()
const BASE_URL = import.meta.env.VITE_BASE_URL;
return(
<>
<section className={styles.section}
onClick={() => navigate(`/detail/${place.id}`)}>
<img src={`${BASE_URL}/${place.image.src}`} alt={place.title}/>
<div> {place.title} </div>
<FavoriteBtn place={place} />
</section>
</>
)
}

