From f9de5d0570787e7dcbf84f81800c76271ebecba9 Mon Sep 17 00:00:00 2001 From: yongaricode Date: Thu, 8 May 2025 13:35:12 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=EB=A6=AC=EB=B7=B0=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=20=EC=8B=9C=20=EB=A1=9C=EB=94=A9=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/icons/book-snap/loading.gif | Bin 0 -> 88551 bytes src/pages/Booksnap/CreateBook.tsx | 8 ++++++++ src/pages/Booksnap/CreateBooksnapReview2.tsx | 9 +++++++++ src/pages/Booksnap/IndiCreateBookReview2.tsx | 9 ++++++++- src/pages/Loading.tsx | 12 ++++++------ 5 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 public/icons/book-snap/loading.gif diff --git a/public/icons/book-snap/loading.gif b/public/icons/book-snap/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..d0d2b2de019675e22b54b18c360032a48c237cea GIT binary patch literal 88551 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 literal 0 HcmV?d00001 diff --git a/src/pages/Booksnap/CreateBook.tsx b/src/pages/Booksnap/CreateBook.tsx index a0697ea..a21a8bd 100644 --- a/src/pages/Booksnap/CreateBook.tsx +++ b/src/pages/Booksnap/CreateBook.tsx @@ -9,6 +9,7 @@ import AddBookstore from '../../components/Booksnap/AddBookstore'; import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline'; import { postIndepBook } from '../../api/booksnap.api'; import cropImage from '../../utils/cropImage'; +import Loading from '../Loading'; export type Option = { bookstoreId: number; @@ -28,8 +29,10 @@ const CreateBook = () => { const [previewList, setPreviewList] = useState([]); // 미리보기용 URL 저장 const [selectedBookstores, setSelectedBookstores] = useState([]); + const [isLoading, setIsLoading] = useState(false); const handleReviewPost = async () => { + setIsLoading(true); const bookstoreIds = selectedBookstores.map((b) => b.bookstoreId); const payload = { @@ -47,6 +50,7 @@ const CreateBook = () => { imageToUpload = await cropImage(url, 80, 120); // 자른 File 반환 } postIndepBook(imageToUpload, payload).then(() => { + setIsLoading(false); nav('/booksnap'); }); }; @@ -60,6 +64,10 @@ const CreateBook = () => { } }; + if (isLoading) { + return ; + } + return (
{/* 헤더 */} diff --git a/src/pages/Booksnap/CreateBooksnapReview2.tsx b/src/pages/Booksnap/CreateBooksnapReview2.tsx index 3aff029..aedec42 100644 --- a/src/pages/Booksnap/CreateBooksnapReview2.tsx +++ b/src/pages/Booksnap/CreateBooksnapReview2.tsx @@ -7,6 +7,7 @@ import WritingReview from '../../components/Zip/WritingReview'; import Button from '../../components/Button/Button'; import { postBookReview } from '../../api/booksnap.api'; import Step from '../../components/Booksnap/Step'; +import Loading from '../Loading'; const CreateBooksnapReview2 = () => { const location = useLocation(); @@ -16,17 +17,25 @@ const CreateBooksnapReview2 = () => { const [rating, setRating] = useState(0); const [review, setReview] = useState(''); + const [isLoading, setIsLoading] = useState(false); + const handleReviewPost = () => { + setIsLoading(true); const payload = { isbn: book.isbn, rating: rating, reviewText: review, }; postBookReview('normal', payload).then((data) => { + setIsLoading(false); nav('/booksnap'); }); }; + if (isLoading) { + return ; + } + return (
{/* 헤더 */} diff --git a/src/pages/Booksnap/IndiCreateBookReview2.tsx b/src/pages/Booksnap/IndiCreateBookReview2.tsx index db0c73e..f8bf1d1 100644 --- a/src/pages/Booksnap/IndiCreateBookReview2.tsx +++ b/src/pages/Booksnap/IndiCreateBookReview2.tsx @@ -8,6 +8,7 @@ import Button from '../../components/Button/Button'; import { postBookReview } from '../../api/booksnap.api'; import Step from '../../components/Booksnap/Step'; import AddBookstore from '../../components/Booksnap/AddBookstore'; +import Loading from '../Loading'; export type Option = { bookstoreId: number; @@ -25,8 +26,10 @@ const IndiCreateBookReview2 = () => { const [review, setReview] = useState(''); const [selectedBookstores, setSelectedBookstores] = useState([]); + const [isLoading, setIsLoading] = useState(false); const handleReviewPost = () => { + setIsLoading(true); const bookstoreIds = selectedBookstores.map((b) => b.bookstoreId); const payload = { @@ -36,11 +39,15 @@ const IndiCreateBookReview2 = () => { reviewText: review, }; postBookReview('indep', payload).then((data) => { - console.log('리뷰 등록 성공'); + setIsLoading(false); nav('/booksnap'); }); }; + if (isLoading) { + return ; + } + return (
{/* 헤더 */} diff --git a/src/pages/Loading.tsx b/src/pages/Loading.tsx index e5d2caf..7c89380 100644 --- a/src/pages/Loading.tsx +++ b/src/pages/Loading.tsx @@ -1,4 +1,4 @@ -import loading_logo from '../../public/icons/login-signup/Logo.png'; +import loading from '../../public/icons/book-snap/loading.gif'; interface LoadingProps { text: string; @@ -6,11 +6,11 @@ interface LoadingProps { const Loading = ({ text }: LoadingProps) => { return ( -
- -
-

{text}

-

잠시만 기다려주세요!

+
+ +
+

{text}

+

잠시만 기다려주세요!

); From 841930192574c57ed7dfc4391bb02bcb9ab9510b Mon Sep 17 00:00:00 2001 From: yongaricode Date: Thu, 8 May 2025 16:38:25 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20Bookie=20API=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/bookie.api.ts | 18 +++++++++ src/pages/Bookie.tsx | 94 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 96 insertions(+), 16 deletions(-) create mode 100644 src/api/bookie.api.ts diff --git a/src/api/bookie.api.ts b/src/api/bookie.api.ts new file mode 100644 index 0000000..bc52df4 --- /dev/null +++ b/src/api/bookie.api.ts @@ -0,0 +1,18 @@ +// utils/chatAPI.ts +import instance from './instance'; + +// 한줄 리뷰 등록 (Spring 서버를 통해 FastAPI 프록시로 전달) +export const sendMessageToChatAPI = async (message: string) => { + try { + const response = await instance.post('/bookie/chat', { message: message }); + + if (response.status === 200) { + return response.data; + } else { + throw new Error('Server responded with error'); + } + } catch (error) { + console.error('❌ chat API 호출 실패:', error); + throw error; + } +}; diff --git a/src/pages/Bookie.tsx b/src/pages/Bookie.tsx index 4eada0a..78c1359 100644 --- a/src/pages/Bookie.tsx +++ b/src/pages/Bookie.tsx @@ -1,16 +1,25 @@ -import Header from '../components/Common/Header'; import bookie from '../../public/icons/bookie/bookie.png'; import MessageBox from '../components/Bookie/MessageBox'; import { useEffect, useRef, useState } from 'react'; import Input from '../components/Bookie/Input'; import { FaRegArrowAltCircleUp } from 'react-icons/fa'; -import { FaAngleLeft } from 'react-icons/fa6'; import { IoCloseOutline } from 'react-icons/io5'; import { useNavigate } from 'react-router-dom'; +import { sendMessageToChatAPI } from '../api/bookie.api'; +import { MdBookmarkAdd } from 'react-icons/md'; +import toast from 'react-hot-toast'; +import { pickBook } from '../api/booksnap.api'; type MessageType = { text: string; type: 'system' | 'user'; + books?: BookCardType[]; +}; + +type BookCardType = { + title: string; + bookId: string; + bookImageUrl: string; }; const Bookie = () => { @@ -18,13 +27,14 @@ const Bookie = () => { const [input, setInput] = useState(''); const nav = useNavigate(); const [isComposing, setIsComposing] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const userName = '이구역독서짱'; const [systemRes, setSystemRes] = useState([ { - text: '안녕하세요! 이구역 독서짱님이 좋아하실만한책을 추천해드리는 Bookie입니다! 더 많은 정보를 알려주시면, 책을 찾아드릴게요.', + text: `안녕하세요! ${userName}님이 좋아하실만한책을 추천해드리는 Bookie입니다! 더 많은 정보를 알려주시면, 책을 찾아드릴게요.`, type: 'system', }, ]); - const userName = '이구역 독서짱'; useEffect(() => { if (endOfMessages.current) { @@ -32,13 +42,24 @@ const Bookie = () => { } }, [systemRes]); - const sendMessage = () => { + // 메세지 보내기 + const sendMessage = async () => { if (!input.trim() || isComposing) return; - if (input.trim() !== '') { - const userMessage: MessageType = { text: input, type: 'user' }; - setSystemRes((prevMessages) => [...prevMessages, userMessage]); - setInput(''); + const userMessage: MessageType = { text: input, type: 'user' }; + setSystemRes((prev) => [...prev, userMessage]); // 사용자 메시지 먼저 출력 + setInput(''); + + try { + const reply = await sendMessageToChatAPI(input); + const systemMessage: MessageType = { text: reply.message, type: 'system', books: reply.books }; + setSystemRes((prev) => [...prev, systemMessage]); // GPT 응답 추가 + } catch (error) { + const errorMessage: MessageType = { + text: '서버와 연결할 수 없습니다.', + type: 'system', + }; + setSystemRes((prev) => [...prev, errorMessage]); } }; @@ -53,10 +74,25 @@ const Bookie = () => { } }; + const handlePickBook = (book: BookCardType) => { + console.log(book); + if (!localStorage.getItem('accessToken')) { + toast.error('로그인이 필요한 서비스입니다.'); + } else { + pickBook(book.bookId).then((data) => { + if (data?.success) { + toast.success(`${book.title}을(를) 책장에 담았어요!`); + } else { + toast.error(`${data?.message}`); + } + }); + } + }; + return (
{/* 헤더 */} -
+
nav('/')}> @@ -69,7 +105,7 @@ const Bookie = () => {
{/* 내용 */} -
+
{/* 설명 */}
{userName} @@ -78,29 +114,55 @@ const Bookie = () => { 책과 서점을 추천해드릴게요!
-
{/* 채팅구역 */}
e.stopPropagation()} // 휠 이벤트 차단 > {systemRes.map((msg, index) => ( - +
+ + {msg.books && msg.books.length > 0 && ( +
+
+ {msg.books.map((book, idx) => ( +
+
+ {book.title} + +
+

{book.title}

+
+ ))} +
+
+ )} +
))} +
{/* 입력창 */} -
+
{input == '' ? ( ) : ( -
+
)} From 8ef2a771c4460e1ec2308e9a45eeb0f89203e197 Mon Sep 17 00:00:00 2001 From: yongaricode Date: Thu, 8 May 2025 16:54:35 +0900 Subject: [PATCH 3/4] =?UTF-8?q?feat:=20Bookie=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=EC=A4=91=20=EB=9E=9C=EB=8D=A4=20=EB=A9=94=EC=84=B8=EC=A7=80=20?= =?UTF-8?q?=EB=9D=84=EC=9B=8C=EC=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants/bookieLoadingMessages.ts | 38 ++++++++++++++++++++++++++ src/pages/Bookie.tsx | 20 ++++++++++++-- 2 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 src/constants/bookieLoadingMessages.ts diff --git a/src/constants/bookieLoadingMessages.ts b/src/constants/bookieLoadingMessages.ts new file mode 100644 index 0000000..d7fe66e --- /dev/null +++ b/src/constants/bookieLoadingMessages.ts @@ -0,0 +1,38 @@ +// utils/bookieLoadingMessages.ts + +export const bookieLoadingMessages = [ + // 📖 책 팁 / 독서 팁 + '📚 하루 10분 독서만 해도 1년에 책 12권은 읽을 수 있어요!', + '🕯️ 자기 전 15분 독서는 스트레스를 68% 줄여준대요.', + '📖 집중이 안 될 땐 10분짜리 짧은 독립출판물부터 시작해보세요.', + '📎 종이책을 읽을 땐 포스트잇을 곁에 두는 습관, 생각 정리에 좋아요.', + '📱 전자책도 좋아요, 하지만 눈을 쉬게 하려면 종이책도 가끔씩은 꼭!', + + // 🎯 문학 퀴즈 / 정보 + '퀴즈! 세계에서 가장 많이 팔린 책은 무엇일까요? (힌트: 성경 말고!)', + '퀴즈! 해리포터 1권의 원제는 무엇일까요?', + '작가가 27번 거절당하고도 출간한 책, 알고 있나요? — 《해리 포터》 시리즈!', + '미국의 국민 시인이라 불리는 작가는 누구일까요? (힌트: ‘풀잎 위에서’)', + '‘책의 날’은 매년 4월 23일! 세르반테스와 셰익스피어가 같은 날 세상을 떠났어요.', + + // 🗂️ 독립출판/인디북스 정보 + '독립출판물은 보통 작가가 직접 기획, 집필, 디자인, 제작까지 한답니다.', + '부키 팁! 독립서점마다 특별한 큐레이션 책장이 있는 거, 알고 계셨나요?', + '‘지금 여기, 내가 만든 책’ — 독립출판의 핵심은 바로 이 말이에요.', + '독립출판물은 1쇄 100부도 가능해요. 나만의 책 만들기도 도전해보세요!', + '서울에는 약 100여 개의 독립서점이 존재해요. 부키가 추천해드릴까요?', + + // 💡 랜덤 흥미 정보 (재미용) + '지구상에서 가장 오래된 책은 기원전 2400년의 ‘죽은 자의 서’랍니다.', + '고서 수집가들 사이에서 가장 비싼 책은 3천억 원이 넘게 거래되기도 했어요!', + '세계 최초의 소설은 일본의 《겐지 이야기》라는 거, 알고 계셨나요?', + '📖 부키는 지금 책향기가 나는 데이터 속으로 잠수 중입니다…', + '책도 사람도, 겉보다 속이 더 중요하답니다. 😊', + + '《책방》이라는 단어는 일본식 한자어예요. 원래는 ‘서점’이 맞답니다!', + '세상에서 가장 오래된 도서관은 기원전 7세기 이집트에 있었어요.', + '어떤 책은 종이를 직접 염색해서 만드는 ‘리소’ 인쇄를 써요!', + '책을 선물하면 기억에 오래 남는대요. 이유는 ‘시간을 주는 거니까’.', + '📦 독립출판은 때로 택배 상자 속 한 줄 편지로 완성돼요.', + '누군가는 밤새워 만든 40쪽짜리 책, 당신이 펼칠 차례예요.', +]; diff --git a/src/pages/Bookie.tsx b/src/pages/Bookie.tsx index 78c1359..6cbd30f 100644 --- a/src/pages/Bookie.tsx +++ b/src/pages/Bookie.tsx @@ -9,6 +9,7 @@ import { sendMessageToChatAPI } from '../api/bookie.api'; import { MdBookmarkAdd } from 'react-icons/md'; import toast from 'react-hot-toast'; import { pickBook } from '../api/booksnap.api'; +import { bookieLoadingMessages } from '../constants/bookieLoadingMessages'; type MessageType = { text: string; @@ -28,6 +29,7 @@ const Bookie = () => { const nav = useNavigate(); const [isComposing, setIsComposing] = useState(false); const [isLoading, setIsLoading] = useState(false); + const [loadingMessage, setLoadingMessage] = useState(''); const userName = '이구역독서짱'; const [systemRes, setSystemRes] = useState([ { @@ -50,6 +52,10 @@ const Bookie = () => { setSystemRes((prev) => [...prev, userMessage]); // 사용자 메시지 먼저 출력 setInput(''); + const random = bookieLoadingMessages[Math.floor(Math.random() * bookieLoadingMessages.length)]; + setLoadingMessage(random); + setIsLoading(true); + try { const reply = await sendMessageToChatAPI(input); const systemMessage: MessageType = { text: reply.message, type: 'system', books: reply.books }; @@ -60,6 +66,9 @@ const Bookie = () => { type: 'system', }; setSystemRes((prev) => [...prev, errorMessage]); + } finally { + setIsLoading(false); + setLoadingMessage(''); } }; @@ -119,11 +128,11 @@ const Bookie = () => {
{/* 채팅구역 */}
e.stopPropagation()} // 휠 이벤트 차단 > {systemRes.map((msg, index) => ( -
+
{msg.books && msg.books.length > 0 && (
@@ -151,7 +160,12 @@ const Bookie = () => { )}
))} - + {isLoading && ( +
+

부키가 책을 고르러 작은 서점 골목으로 들어갔어요...📚

+

{loadingMessage}

+
+ )}
From 495d02c57c67777edb6f0a778363d20f75b6a9bd Mon Sep 17 00:00:00 2001 From: yongaricode Date: Thu, 8 May 2025 17:02:42 +0900 Subject: [PATCH 4/4] =?UTF-8?q?feat:=20Booksnap=20=EB=A1=9C=EB=94=A9=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Booksnap/BookSnap.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/pages/Booksnap/BookSnap.tsx b/src/pages/Booksnap/BookSnap.tsx index 66ee98b..de11e1e 100644 --- a/src/pages/Booksnap/BookSnap.tsx +++ b/src/pages/Booksnap/BookSnap.tsx @@ -6,7 +6,6 @@ import Loading from '../Loading'; import WriteButton from '../../components/Booksnap/WriteButton'; import { getReview } from '../../api/booksnap.api'; import Toast from '../../components/Common/Toast'; -import { useNavigate } from 'react-router-dom'; import BooksnapHeader from '../../components/Header/BooksnapHeader'; const BookSnap = () => { @@ -17,9 +16,11 @@ const BookSnap = () => { const [isBottom, setIsBottom] = useState(false); const mainRef = useRef(null); const isLastRef = useRef(false); + const [isLoading, setIsLoading] = useState(false); // 리뷰 목록 받아오기 const getReviews = async () => { + setIsLoading(true); try { const data = await getReview(filter, page); setReview((prev) => (page === 1 ? data.data.booksnapPreview : [...prev, ...data.data.booksnapPreview])); @@ -27,6 +28,8 @@ const BookSnap = () => { setIsBottom(false); } catch (error) { console.error('리뷰를 불러오는 중 에러 발생:', error); + } finally { + setIsLoading(false); } }; @@ -83,6 +86,10 @@ const BookSnap = () => { } }, []); + if (isLoading) { + return ; + } + if (!review) { return ; }