본문 바로가기

사이드 프로젝트

카페 추천 웹사이트(카카오맵 API 환경변수 설정, 마이페이지 컴포넌트 생성 및 css)

.env파일에 환경변수를 설정한다. = 뒤에 개인 API키 삽입

REACT_APP_KAKAO_KEY=89fd30d4

 

index.html에 scirpt 추가

<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=%REACT_APP_KAKAO_KEY%"></script>

 

 

카카오맵 지도가 들어가는 페이지 코드
CafeDetail.js

import React, { useEffect, useRef } from "react";
import styles from './CafeDetail.module.css';
import { Link, useParams, useNavigate } from "react-router-dom";

const { kakao } = window;

export default function CafeDetail() {
    const { id } = useParams();
    const container = useRef(null); // 지도 데이터 접근
    const navigate = useNavigate(); // useNavigate 훅을 사용하여 페이지 이동

    //카페 데이터 (예시 데이터)
    const cafes = [
        { id : 1, name: "그릿비", region: "울산", category: "뷰맛집", imageUrl: require('../img/view1.jpg'), latitude:35.34521795854005, longtitude:129.32153486193013 },
        { id : 2, name: "롤링커피", region: "울산", category: "커피맛집", imageUrl:  require('../img/coffe1.jpg'), latitude:35.55061889626061, longtitude:129.29369433796782 },
        { id : 3, name: "아베베베이커리", region: "서울", category: "빵맛집", imageUrl:  require('../img/bread1.jpg'), latitude:37.56953587727422, longtitude:126.99993491306338 },
        { id : 4, name: "델문도", region: "제주", category: "뷰맛집", imageUrl: require('../img/view2.jpg'), latitude:33.543694963787615, longtitude:126.66874393114894 },
    ];

    // 선택한 카페 정보 찾기
    const cafe = cafes.find(cafe => cafe.id === parseInt(id));

    useEffect(() => {
        const position = new kakao.maps.LatLng(cafe.latitude, cafe.longtitude); //카페의 좌표로 위치 설정
        const options = {
            center: position,
            level: 3,
        };
        const map = new kakao.maps.Map(container.current, options);

        //마커 생성
        const marker = new kakao.maps.Marker({
            position: position,
        });
        marker.setMap(map);
    }, [cafe.latitude, cafe.longtitude]);

    if (!cafe) {
        return <p>카페 정보를 찾을 수 없습니다.</p>;
    }

    return (
        <div className={styles.bgImg}>
            <h1 className={styles.header}>
                <Link to="/" className={styles.title}>CAFE 정보</Link>
            </h1>

            <div className={styles.container}>
                <div className={styles.cafeDetail}>
                    <img src={cafe.imageUrl} alt={cafe.name} className={styles.cafeImage} />
                    <h2 className={styles.cafeTitle}>{cafe.name}</h2>
                    <p className={styles.cafeInfo}>{cafe.region} | {cafe.category}</p>
                    <p className={styles.cafeDescription}>{cafe.description}</p>

                    <div style={{ width: "90%", height: "600px", margin: "0 auto" }} ref={container}></div>

                    <button onClick={() => navigate('/cafeList')} className={styles.backButton}>
                        뒤로가기
                    </button>
                </div>
            </div>
        </div>
    );
}

 

그 다음 

CafeMypage.js코드

import React, { useState } from "react";
import styles from './CafeMypage.module.css';

const initialCafes = [
    { id: 1, name: "그릿비", region: "울산", category: "뷰맛집", description: "아름다운 바다를 볼 수 있는 카페" },
    { id: 2, name: "롤링커피", region: "울산", category: "커피맛집", description: "신선한 커피를 제공하는 카페" },
    { id: 3, name: "아베베베이커리", region: "서울", category: "빵맛집", description: "맛있는 빵과 디저트를 판매하는 카페" },
];

export default function CafeMypage() {
    const [cafes, setCafes] = useState(initialCafes);
    const [editCafe, setEditCafe] = useState(null);
    const [newName, setNewName] = useState('');
    const [newRegion, setNewRegion] = useState('');
    const [newCategory, setNewCategory] = useState('');
    const [newDescription, setNewDescription] = useState('');

    const handleEdit = (cafe) => {
        setEditCafe(cafe.id);
        setNewName(cafe.name);
        setNewRegion(cafe.region);
        setNewCategory(cafe.category);
        setNewDescription(cafe.description);
    };

    const handleUpdate = () => {
        setCafes(cafes.map(cafe =>
            cafe.id === editCafe
                ? { ...cafe, name: newName, region: newRegion, category: newCategory, description: newDescription }
                : cafe
        ));
        setEditCafe(null);
        setNewName('');
        setNewRegion('');
        setNewCategory('');
        setNewDescription('');
    };

    const handleDelete = (id) => {
        setCafes(cafes.filter(cafe => cafe.id !== id));
    };

    return (
        <div className={styles.mypageContainer}>
            <h1>내 카페 목록</h1>
            <ul>
                {cafes.map(cafe => (
                    <li key={cafe.id} className={styles.cafeItem}>
                        <h2>{cafe.name}</h2>
                        <p>{cafe.region} | {cafe.category}</p>
                        <p>{cafe.description}</p>
                        <button onClick={() => handleEdit(cafe)}>수정</button>
                        <button onClick={() => handleDelete(cafe.id)}>삭제</button>
                    </li>
                ))}
            </ul>

            {editCafe && (
                <div className={styles.editForm}>
                    <h2>카페 수정하기</h2>
                    <input
                        type="text"
                        value={newName}
                        onChange={(e) => setNewName(e.target.value)}
                        placeholder="카페 이름"
                    />
                    <input
                        type="text"
                        value={newRegion}
                        onChange={(e) => setNewRegion(e.target.value)}
                        placeholder="지역"
                    />
                    <input
                        type="text"
                        value={newCategory}
                        onChange={(e) => setNewCategory(e.target.value)}
                        placeholder="카테고리"
                    />
                    <input
                        type="text"
                        value={newDescription}
                        onChange={(e) => setNewDescription(e.target.value)}
                        placeholder="설명"
                    />
                    <button onClick={handleUpdate}>수정 완료</button>
                    <button onClick={() => setEditCafe(null)}>취소</button>
                </div>
            )}
        </div>
    );
}

 

CafeMypage.modulde.css코드

css


/* 기본 스타일 */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

a {
    text-decoration: none;
    color: black;
}

li {
    list-style: none;
}

img {
    display: block;
    width: 100%;
}

/* 마이페이지 컨테이너 */
.mypageContainer {
    padding: 20px;
    background-color: #f9f9f9; /* 배경색 변경 */
    border-radius: 8px; /* 둥근 모서리 */
    max-width: 800px; /* 최대 너비 설정 */
    margin: auto; /* 중앙 정렬 */
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); /* 그림자 효과 */
}

/* 카페 아이템 스타일 */
.cafeItem {
    border: 1px solid #ccc;
    padding: 15px;
    margin-bottom: 15px;
    border-radius: 5px; /* 둥근 모서리 */
    background-color: #ffffff; /* 흰색 배경 */
    transition: box-shadow 0.3s; /* 애니메이션 효과 */
}

.cafeItem:hover {
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); /* 마우스 오버 시 그림자 효과 */
}

/* 수정 폼 스타일 */
.editForm {
    margin-top: 20px;
    padding: 15px;
    border: 1px solid #007bff; /* 파란색 테두리 */
    border-radius: 5px; /* 둥근 모서리 */
    background-color: #e7f1ff; /* 연한 파란색 배경 */
}

/* 입력 필드 스타일 */
.editForm input {
    display: block;
    margin-bottom: 10px;
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 5px; /* 둥근 모서리 */
    width: 100%; /* 전체 너비 */
    font-size: 14px; /* 글자 크기 */
    transition: border-color 0.3s; /* 테두리 색상 변경 애니메이션 */
}

.editForm input:focus {
    border-color: #007bff; /* 포커스 시 파란색 테두리 */
    outline: none; /* 기본 아웃라인 제거 */
}

/* 버튼 스타일 */
button {
    padding: 10px 15px;
    border: none;
    border-radius: 5px; /* 둥근 모서리 */
    background-color: #007bff; /* 파란색 배경 */
    color: white; /* 흰색 글씨 */
    cursor: pointer; /* 커서 포인터 */
    transition: background-color 0.3s; /* 배경색 변경 애니메이션 */
}

button:hover {
    background-color: #0056b3; /* 마우스 오버 시 어두운 파란색 */
}

button:focus {
    outline: none; /* 기본 아웃라인 제거 */
}

 

 

결과 화면

 

추후 디자인 더 필요

 

오늘은 여기까지~