Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const BookSearchBottomSheet = ({ isOpen, onClose, onSelectBook }: BookSearchBott
setSearchQuery,
handleTabChange,
loadInitialData,
performSearch,
} = useBookSearch();

// 컴포넌트가 열릴 때 초기 데이터 로드
Expand Down Expand Up @@ -64,7 +65,9 @@ const BookSearchBottomSheet = ({ isOpen, onClose, onSelectBook }: BookSearchBott
};

const handleSearch = () => {
console.log('검색:', searchQuery);
if (searchQuery.trim()) {
performSearch(searchQuery.trim());
}
};

const handleClearSearch = () => {
Expand Down
99 changes: 84 additions & 15 deletions src/components/common/BookSearchBottomSheet/useBookSearch.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useState, useEffect } from 'react';
import { getSavedBooks, type SavedBook } from '@/api/books/getSavedBooks';
import { getSearchBooks, convertToSearchedBooks, type SearchedBook } from '@/api/books/getSearchBooks';
import type { Book } from './BookList';
import type { TabType } from './BookSearchTabs';

Expand All @@ -9,8 +10,10 @@ export const useBookSearch = () => {
const [activeTab, setActiveTab] = useState<TabType>('saved');
const [savedBooks, setSavedBooks] = useState<SavedBook[]>([]);
const [groupBooks, setGroupBooks] = useState<SavedBook[]>([]);
const [searchResults, setSearchResults] = useState<SearchedBook[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [searchTimeoutId, setSearchTimeoutId] = useState<NodeJS.Timeout | null>(null);

// API에서 받은 데이터를 Book 타입으로 변환하는 함수
const convertSavedBookToBook = (savedBook: SavedBook): Book => ({
Expand All @@ -21,6 +24,15 @@ export const useBookSearch = () => {
isbn: savedBook.isbn,
});

// 검색 결과를 Book 타입으로 변환하는 함수
const convertSearchedBookToBook = (searchedBook: SearchedBook): Book => ({
id: searchedBook.id,
title: searchedBook.title,
author: searchedBook.author,
cover: searchedBook.coverUrl,
isbn: searchedBook.isbn,
});

// 저장한 책 데이터 가져오기
const fetchSavedBooks = async () => {
try {
Expand Down Expand Up @@ -63,22 +75,68 @@ export const useBookSearch = () => {
}
};

// 실제 검색 API 호출 함수
const performSearch = async (query: string) => {
if (!query.trim()) {
setSearchResults([]);
return;
}

try {
setIsLoading(true);
setError(null);

const response = await getSearchBooks(query.trim(), 1, true);

if (response.isSuccess) {
const convertedResults = convertToSearchedBooks(response.data.searchResult);
setSearchResults(convertedResults);
} else {
setError(response.message || '검색에 실패했습니다.');
setSearchResults([]);
}
} catch (err) {
console.error('검색 오류:', err);
setError('검색 중 오류가 발생했습니다.');
setSearchResults([]);
} finally {
setIsLoading(false);
}
};

// 검색어 변경 핸들러 (디바운싱 적용)
const handleSearchQueryChange = (query: string) => {
setSearchQuery(query);

if (searchTimeoutId) {
clearTimeout(searchTimeoutId);
}

if (query.trim()) {
const timeoutId = setTimeout(() => {
performSearch(query);
}, 300);
setSearchTimeoutId(timeoutId);
} else {
setSearchResults([]);
setError(null);
}
};

// 필터링 로직
useEffect(() => {
// 검색어가 있으면 검색 결과를 표시
if (searchQuery.trim()) {
const convertedSearchResults = searchResults.map(convertSearchedBookToBook);
setFilteredBooks(convertedSearchResults);
return;
}

// 검색어가 없으면 저장된 책들을 표시
const currentTabBooks = activeTab === 'saved' ? savedBooks : groupBooks;
const convertedBooks = currentTabBooks.map(convertSavedBookToBook);

if (searchQuery.trim() === '') {
setFilteredBooks(convertedBooks);
} else {
const filtered = convertedBooks.filter(
book =>
book.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
book.author.toLowerCase().includes(searchQuery.toLowerCase()),
);
setFilteredBooks(filtered);
}
}, [searchQuery, activeTab, savedBooks, groupBooks]);
setFilteredBooks(convertedBooks);
}, [searchQuery, activeTab, savedBooks, groupBooks, searchResults]);

// 탭 변경 핸들러
const handleTabChange = async (tab: TabType) => {
Expand All @@ -103,10 +161,20 @@ export const useBookSearch = () => {
};

// 현재 상태 계산
const isSearchMode = searchQuery.trim() !== '';
const currentTabBooks = activeTab === 'saved' ? savedBooks : groupBooks;
const hasBooks = currentTabBooks.length > 0;
const hasBooks = isSearchMode ? searchResults.length > 0 : currentTabBooks.length > 0;
const showEmptyState = !isLoading && !error && !hasBooks;
const showTabs = searchQuery.trim() === '' && !showEmptyState;
const showTabs = !isSearchMode && !showEmptyState;

// 컴포넌트 언마운트 시 타이머 정리
useEffect(() => {
return () => {
if (searchTimeoutId) {
clearTimeout(searchTimeoutId);
}
};
}, [searchTimeoutId]);

return {
// State
Expand All @@ -120,8 +188,9 @@ export const useBookSearch = () => {
showTabs,

// Actions
setSearchQuery,
setSearchQuery: handleSearchQueryChange,
handleTabChange,
loadInitialData,
performSearch,
};
};