diff --git a/src/App.jsx b/src/App.jsx index c0e9f18..100d5d1 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -3,7 +3,7 @@ import { Routes, Route, useLocation } from "react-router-dom"; import Splash from "./pages/Splash"; import OnBoarding from "./pages/OnBoarding"; import Home from "./pages/Home"; -import Signup from "./pages/SignUp"; +import Signup from "./pages/Signup"; import Map from "./pages/Map"; import BottomNav from "./components/BottomNav"; import TopNav from "./components/TopNav"; @@ -22,7 +22,6 @@ function App() { // 바텀nav바를 숨길 경로들 const hideBottomNavPaths = [ "/splash", - "/", "/signup", "/login", "/chat/room/buy", @@ -35,7 +34,6 @@ function App() { // 탑nav바를 숨길 경로들 const hideTopNavPaths = [ "/splash", - "/", "/login", "/signup", "/chat/room/final", diff --git a/src/api/index.js b/src/api/index.js index b44b572..71e265d 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -14,41 +14,25 @@ const api = axios.create({ withCredentials: true, }); -// GET 요청 -export const get = (url, data) => api.get(url, data); - -// POST 요청 -export const post = (url, data) => api.post(url, data); - -// PUT 요청 -export const put = (url, data) => api.put(url, data); - -// DELETE 요청 -export const del = (url) => api.delete(url); - -// PATCH 요청 -export const patch = (url, data) => api.patch(url, data); - export default api; -// // ✅ 모든 요청에 자동으로 accessTok en 추가 -// api.interceptors.request.use( -// async (config) => { -// try { -// const tokenData = localStorage.getItem("userTokens"); -// if (tokenData) { -// const { accessToken } = JSON.parse(tokenData); -// if (accessToken) { -// config.headers["Authorization"] = `Bearer ${accessToken}`; -// } -// } -// } catch (error) { -// console.error("토큰 불러오기 실패:", error); -// } -// return config; -// }, -// (error) => Promise.reject(error) -// ); +// ✅ 모든 요청에 자동으로 accessTok en 추가 +api.interceptors.request.use( + async (config) => { + try { + const tokenData = localStorage.getItem("access_token"); + console.log(tokenData); + if (tokenData) { + config.headers["Authorization"] = `Bearer ${tokenData}`; + } + console.log(config); + } catch (error) { + console.error("토큰 불러오기 실패:", error); + } + return config; + }, + (error) => Promise.reject(error) +); // // 🔥 응답 인터셉터: 리프레시 토큰으로 재발급 처리 // api.interceptors.response.use( @@ -57,7 +41,7 @@ export default api; // if (error.response?.status === 401) { // console.log("토큰 만료됨, 리프레시 토큰 사용!"); -// const tokenData = localStorage.getItem("userTokens"); +// const tokenData = localStorage.getItem("refresh_token"); // if (tokenData) { // const { refreshToken } = JSON.parse(tokenData); // try { @@ -85,3 +69,18 @@ export default api; // return Promise.reject(error); // } // ); + +// GET 요청 +export const get = (url, data) => api.get(url, data); + +// POST 요청 +export const post = (url, data) => api.post(url, data); + +// PUT 요청 +export const put = (url, data) => api.put(url, data); + +// DELETE 요청 +export const del = (url, data) => api.delete(url, data); + +// PATCH 요청 +export const patch = (url, data) => api.patch(url, data); diff --git a/src/api/wish-controller/wishPost.js b/src/api/wish-controller/wishPost.js index f757640..1a19450 100644 --- a/src/api/wish-controller/wishPost.js +++ b/src/api/wish-controller/wishPost.js @@ -1,6 +1,7 @@ import { post } from "./../index"; // 좋아요 API 호출 export const likeSpace = async (spaceId) => { + console.log(spaceId); try { const res = await post(`/api/v1/user/spaces/${spaceId}/like`); return res.data; diff --git a/src/components/ItemModal.jsx b/src/components/ItemModal.jsx index faa9d86..ee98880 100644 --- a/src/components/ItemModal.jsx +++ b/src/components/ItemModal.jsx @@ -17,9 +17,12 @@ const ItemModal = ({ isOpen, onClose, item }) => { const [liked, setLiked] = useState(false); // 상태값 저장 if (!isOpen || !item) return null; - const images = item.images && item.images.length > 0 ? item.images : [null]; // 기본 이미지 처리 - const total = 5; - + const images = + item.coverImageUrl && item.coverImageUrl.length > 0 + ? item.coverImageUrl + : [null]; // 기본 이미지 처리 + const total = 1; + console.log(item); const handlePrev = () => { setCurrentIndex((prev) => (prev === 0 ? total - 1 : prev - 1)); }; @@ -30,7 +33,7 @@ const ItemModal = ({ isOpen, onClose, item }) => { const handleLikeToggle = async () => { try { - const spaceId = 123; // 임의 ID + const spaceId = item.spaceId; // 임의 ID if (liked) { // 이미 좋아요 상태라면 → 취소 요청 diff --git a/src/pages/Map.jsx b/src/pages/Map.jsx index 9283a56..64cc4db 100644 --- a/src/pages/Map.jsx +++ b/src/pages/Map.jsx @@ -276,7 +276,17 @@ const Map = () => { setInitialHeight(140); }} > - + + {item.spaceName + {item.price.toLocaleString()}원
{ ))} +
diff --git a/src/pages/chatPage/ChatPage.jsx b/src/pages/chatPage/ChatPage.jsx index b4b36b3..e78acff 100644 --- a/src/pages/chatPage/ChatPage.jsx +++ b/src/pages/chatPage/ChatPage.jsx @@ -25,86 +25,6 @@ const dummyData = [ buildingImage: "https://via.placeholder.com/50", timestamp: new Date(2024, 7, 15, 9, 10), }, - { - id: 3, - name: "이영희", - lastMessage: "계약 관련 문의드립니다.", - time: "어제", - unreadCount: 1, - profile: "https://via.placeholder.com/40", - buildingImage: "https://via.placeholder.com/50", - timestamp: new Date(2024, 7, 14, 20, 30), - }, - { - id: 4, - name: "박민수", - lastMessage: "내일 뵙겠습니다.", - time: "8월 10일", - unreadCount: 0, - profile: "https://via.placeholder.com/40", - buildingImage: "https://via.placeholder.com/50", - timestamp: new Date(2024, 7, 10, 12, 0), - }, - { - id: 5, - name: "최지우", - lastMessage: "네 알겠습니다~", - time: "8월 5일", - unreadCount: 5, - profile: "https://via.placeholder.com/40", - buildingImage: "https://via.placeholder.com/50", - timestamp: new Date(2024, 7, 5, 18, 45), - }, - { - id: 6, - name: "윤하늘", - lastMessage: "사진 보내드릴게요.", - time: "8월 1일", - unreadCount: 0, - profile: "https://via.placeholder.com/40", - buildingImage: "https://via.placeholder.com/50", - timestamp: new Date(2024, 7, 1, 14, 15), - }, - { - id: 7, - name: "장보고", - lastMessage: "감사합니다!", - time: "7월 28일", - unreadCount: 0, - profile: "https://via.placeholder.com/40", - buildingImage: "https://via.placeholder.com/50", - timestamp: new Date(2024, 6, 28, 11, 0), - }, - { - id: 8, - name: "오세훈", - lastMessage: "혹시 내일 시간 괜찮으세요?", - time: "7월 25일", - unreadCount: 2, - profile: "https://via.placeholder.com/40", - buildingImage: "https://via.placeholder.com/50", - timestamp: new Date(2024, 6, 25, 17, 50), - }, - { - id: 9, - name: "서지수", - lastMessage: "서류 전달했습니다.", - time: "7월 21일", - unreadCount: 0, - profile: "https://via.placeholder.com/40", - buildingImage: "https://via.placeholder.com/50", - timestamp: new Date(2024, 6, 21, 13, 30), - }, - { - id: 10, - name: "정우성", - lastMessage: "네 확인했습니다.", - time: "7월 18일", - unreadCount: 0, - profile: "https://via.placeholder.com/40", - buildingImage: "https://via.placeholder.com/50", - timestamp: new Date(2024, 6, 18, 9, 20), - }, ]; const ChatPage = () => { diff --git a/src/pages/chatPage/ChatRoomFinalPage.jsx b/src/pages/chatPage/ChatRoomFinalPage.jsx index 2051b75..6320f6f 100644 --- a/src/pages/chatPage/ChatRoomFinalPage.jsx +++ b/src/pages/chatPage/ChatRoomFinalPage.jsx @@ -26,7 +26,7 @@ const ChatRoomFinalPage = () => { { - navigate("/main"); + navigate("/home"); }} > 홈으로 가기 diff --git a/src/pages/chatPage/ChatRoomPage.jsx b/src/pages/chatPage/ChatRoomPage.jsx index 5a2f61b..fe69a4b 100644 --- a/src/pages/chatPage/ChatRoomPage.jsx +++ b/src/pages/chatPage/ChatRoomPage.jsx @@ -1,6 +1,6 @@ -import { useParams, useNavigate } from "react-router-dom"; +import { useParams, useNavigate, useLocation } from "react-router-dom"; import styled from "styled-components"; -import { useState } from "react"; +import { useState, useEffect, useRef } from "react"; import LeftArrowIcon from "../../assets/icons/leftArrowIconBlack.svg"; import GrayIcon from "../../assets/icons/grayMarker.svg"; import SendIcon from "../../assets/icons/sendIcon.svg"; @@ -18,6 +18,9 @@ const dummyPlace = { const ChatRoomPage = () => { const { id } = useParams(); const navigate = useNavigate(); + const location = useLocation(); + const { item } = location.state || {}; // state 없으면 {} 처리 + const chatEndRef = useRef(null); const [messages, setMessages] = useState([ { id: 1, @@ -113,11 +116,28 @@ const ChatRoomPage = () => { ]); const [input, setInput] = useState(""); + useEffect(() => { + scrollToBottom(); + }, [messages]); + + const now = new Date(); + const hours = now.getHours(); + const minutes = now.getMinutes().toString().padStart(2, "0"); + + const ampm = hours >= 12 ? "오후" : "오전"; + const displayHour = hours % 12 || 12; + const time = `${ampm} ${displayHour}:${minutes}`; + + // 스크롤을 맨 아래로 이동시키는 함수 + const scrollToBottom = () => { + chatEndRef.current?.scrollIntoView({ behavior: "smooth" }); + }; + const sendMessage = () => { if (!input.trim()) return; setMessages([ ...messages, - { id: Date.now(), text: input, sender: "me", time: "오후 5:40" }, + { id: Date.now(), text: input, sender: "me", time }, ]); setInput(""); }; @@ -145,7 +165,7 @@ const ChatRoomPage = () => { item @@ -165,9 +185,11 @@ const ChatRoomPage = () => { alt="marker" style={{ width: "auto", height: "auto" }} /> - {dummyPlace.location} + {item ? item.location : "서울 특별시 종로 1가"} - {dummyPlace.price.toLocaleString()}원 + + {item ? item.price.toLocaleString() : "500,000"}원 +
@@ -201,6 +223,8 @@ const ChatRoomPage = () => { )} ))} + {/* 스크롤 끝 ref */} +
{/* 입력창 */} diff --git a/src/pages/myPage/MyPage.jsx b/src/pages/myPage/MyPage.jsx index 797c9ff..2b77713 100644 --- a/src/pages/myPage/MyPage.jsx +++ b/src/pages/myPage/MyPage.jsx @@ -101,9 +101,9 @@ const MyPage = () => { const [likeOpen, setLikeOpen] = useState(false); const [hostOpen, setHostOpen] = useState(false); const [selectedItem, setSelectedItem] = useState(null); - const [reserveCount, setReserveCount] = useState(1); - const [progressCount, setProgressCount] = useState(1); - const [doneCount, setDoneCount] = useState(1); + const [reserveCount, setReserveCount] = useState(2); + const [progressCount, setProgressCount] = useState(0); + const [doneCount, setDoneCount] = useState(0); return ( diff --git a/src/pages/post/PostingCreatePage.jsx b/src/pages/post/PostingCreatePage.jsx index 3fb2299..007c228 100644 --- a/src/pages/post/PostingCreatePage.jsx +++ b/src/pages/post/PostingCreatePage.jsx @@ -25,10 +25,23 @@ const PostingCreatePage = () => { area: "", // 전용면적 (㎡) }); + // editingData → form 형태로 변환 + const mapEditingDataToForm = (data) => ({ + price: data.price || data.rentalFee || "", + subText: data.subText || "", // editingData에 없으니 빈값 + location: data.location || data.address || "", + subLocation: data.subLocation || "", // editingData에 없음 + maxDays: data.maxDays || "", // editingData에 없음 + images: data.coverImageUrl ? [data.coverImageUrl] : [], // 배열로 통일 + buildingUsage: data.buildingUsage || "", // editingData에 없음 + floor: data.floor?.toString() || "", // 숫자 → 문자열 변환 + area: data.area || "", // editingData에 없음 + }); + // 수정 모드일 때 초기화 useEffect(() => { if (editingData) { - setForm(editingData); + setForm(mapEditingDataToForm(editingData)); } }, [editingData]); @@ -70,10 +83,10 @@ const PostingCreatePage = () => { const handleSubmit = () => { if (isEdit) { - navigate("/main"); + navigate("/home"); } else { console.log("새 매물 등록:", form); - navigate("/main"); + navigate("/home"); } }; diff --git a/src/pages/post/PostingDetailPage.jsx b/src/pages/post/PostingDetailPage.jsx index 1d5bdbd..9133396 100644 --- a/src/pages/post/PostingDetailPage.jsx +++ b/src/pages/post/PostingDetailPage.jsx @@ -1,32 +1,12 @@ import styled from "styled-components"; import React, { useState } from "react"; -import { useParams, useNavigate } from "react-router-dom"; +import { useParams, useNavigate, useLocation } from "react-router-dom"; import LeftArrow from "../../assets/icons/leftArrowIcon.svg"; // 좌측 화살표 (하얀색) import RightArrow from "../../assets/icons/rightArrowIcon.svg"; // 우측 화살표 (하얀색) import HeartIcon from "../../assets/icons/heartIcon.svg"; import HeartActiveIcon from "../../assets/icons/activeIcons/heartActiveIcon.svg"; import GrayMarkerIcon from "../../assets/icons/grayMarker.svg"; import StarIcon from "../../assets/icons/star.svg"; -const dummyPosting = { - id: 1, - price: 100000, - subText: "한줄소개", - location: "대구 북구 대학로 71", - subLocation: "2층", - maxDays: 7, - images: [ - "https://via.placeholder.com/500x300?text=Image1", - "https://via.placeholder.com/500x300?text=Image2", - "https://via.placeholder.com/500x300?text=Image3", - ], - buildingUsage: "근린생활시설", // 건축물 용도 - floor: "2", // 해당 층 - area: "45", // 전용면적 (㎡) - // 기존에 있던 데이터 - distance: 700, - reviews: 16, - rating: 4.0, -}; const dummyHost = { id: 1, @@ -37,12 +17,17 @@ const dummyHost = { }; const PostingDetailPage = () => { const navigate = useNavigate(); - const { price, rating, reviews, subText, location, images } = dummyPosting; + const location = useLocation(); + const { item } = location.state || {}; // state 없으면 {} 처리 const { id } = useParams(); const [currentIndex, setCurrentIndex] = useState(0); const [liked, setLiked] = useState(false); // 상태값 저장 - const total = 5; + const images = + item.coverImageUrl && item.coverImageUrl.length > 0 + ? item.coverImageUrl + : [null]; // 기본 이미지 처리 + const total = 1; const handlePrev = () => { setCurrentIndex((prev) => (prev === 0 ? total - 1 : prev - 1)); @@ -97,23 +82,23 @@ const PostingDetailPage = () => { justifyContent: "space-between", }} > - {price.toLocaleString()}원 + {item.price.toLocaleString()}원 { - navigate("/post/create", { state: dummyPosting }); + navigate("/post/create", { state: item }); }} > 수정하기
- {subText} + {item.subText ? item.subText : null} - marker {location} + marker {item.location} - star {rating}{" "} + star {item.rating}{" "} - ({reviews}) + ({item.reviews}) @@ -129,16 +114,16 @@ const PostingDetailPage = () => { 제1종근린생활시설 - - 1층 / 6층 + + 1층 - 140.82㎡ + 140.82 ㎡ - 140.82㎡ + 7 일
@@ -174,7 +159,7 @@ const PostingDetailPage = () => { { - navigate(`/chat/room/${id}`); + navigate(`/chat/room/${id}`, { state: { item } }); }} > 문의하기 diff --git a/src/stores/useHistoryStore.js b/src/stores/useHistoryStore.js new file mode 100644 index 0000000..aec7c1d --- /dev/null +++ b/src/stores/useHistoryStore.js @@ -0,0 +1,46 @@ +import { create } from "zustand"; + +const useHistoryStore = create((set) => ({ + // 예약 내역 + reservationHistory: [], + + // 진행중 내역 + ongoingHistory: [], + + // 완료 내역 + completedHistory: [], + + // 추가 (예: 예약 추가) + addReservation: (item) => + set((state) => ({ + reservationHistory: [...state.reservationHistory, item], + })), + + // 상태 이동 (예약 → 진행중) + moveToOngoing: (id) => + set((state) => { + const item = state.reservationHistory.find((r) => r.id === id); + return { + reservationHistory: state.reservationHistory.filter((r) => r.id !== id), + ongoingHistory: [ + ...state.ongoingHistory, + { ...item, status: "ongoing" }, + ], + }; + }), + + // 상태 이동 (진행중 → 완료) + completeReservation: (id) => + set((state) => { + const item = state.ongoingHistory.find((r) => r.id === id); + return { + ongoingHistory: state.ongoingHistory.filter((r) => r.id !== id), + completedHistory: [ + ...state.completedHistory, + { ...item, status: "completed" }, + ], + }; + }), +})); + +export default useHistoryStore;