1+ 'use client' ;
2+
3+ import { useSearchParams } from 'next/navigation' ;
4+ import { useState , useEffect , Suspense } from 'react' ;
5+ import Header from '../../components/Header' ;
6+ import Footer from '../../components/Footer' ;
7+ import NoImage from '../../components/NoImage' ;
8+ import SearchBar from '../../components/SearchBar' ;
9+
10+ // SearchParams를 사용하는 컴포넌트를 분리
11+ const SearchResults = ( ) => {
12+ const searchParams = useSearchParams ( ) ;
13+ const query = searchParams . get ( 'q' ) ;
14+
15+ // 페이지네이션 관련 상태
16+ const [ currentPage , setCurrentPage ] = useState ( 1 ) ;
17+ const [ totalResults , setTotalResults ] = useState ( 0 ) ; // 전체 검색 결과 수
18+ const itemsPerPage = 10 ; // 페이지당 항목 수
19+
20+ // 서버에서 받아올 실제 검색 결과
21+ const [ fetchedResults , setFetchedResults ] = useState ( [ ] ) ;
22+ const [ isLoading , setIsLoading ] = useState ( false ) ;
23+ const [ error , setError ] = useState ( null ) ;
24+
25+ // query 또는 currentPage가 바뀔 때마다 서버 요청
26+ useEffect ( ( ) => {
27+ if ( ! query ) {
28+ setFetchedResults ( [ ] ) ;
29+ return ;
30+ }
31+ setIsLoading ( true ) ;
32+ setError ( null ) ;
33+ const apiPage = currentPage - 1 ; // API에 0부터 시작하는 페이지 인덱스 전달
34+ const url = `/api/api/drugs/search` ;
35+ const body = {
36+ query : query ,
37+ page : apiPage ,
38+ size : itemsPerPage ,
39+ } ;
40+
41+ fetch (
42+ url , {
43+ method : 'POST' ,
44+ headers : { 'Content-Type' : 'application/json' } ,
45+ body : JSON . stringify ( body ) ,
46+ } )
47+ . then ( res => {
48+ if ( ! res . ok ) throw new Error ( '서버 에러' ) ;
49+ return res . json ( ) ;
50+ } )
51+ . then ( data => {
52+ const list = data . data ;
53+ setFetchedResults ( list ) ;
54+ setTotalResults ( list . length ) ;
55+ } )
56+ . catch ( err => setError ( err . message ) )
57+ . finally ( ( ) => setIsLoading ( false ) ) ;
58+ } , [ query , currentPage ] ) ;
59+
60+ // const [selectedType, setSelectedType] = useState('all');
61+ // const [sortBy, setSortBy] = useState('name');
62+ // const [showTypeDropdown, setShowTypeDropdown] = useState(false);
63+ // const [showSortDropdown, setShowSortDropdown] = useState(false);
64+
65+
66+
67+ // // 임시 검색 결과 데이터
68+ // const mockResults = [
69+ // {
70+ // id: 1,
71+ // name: "타이레놀",
72+ // category: "일반 의약품",
73+ // company: "(주)한국얀센 / Janssen Korea",
74+ // effect: "아세트아미노펜 과립",
75+ // symptoms: ["감기로 인한 발열 및 동통(통증), 두통, 신경통, 근육통, 월경통, 염좌통(삔 통증)"],
76+ // image: null
77+ // },
78+ // {
79+ // id: 2,
80+ // name: "부루펜",
81+ // category: "일반 의약품",
82+ // company: "삼일제약(주) / Samil",
83+ // effect: "이부프로펜",
84+ // symptoms: ["류마티양 관절염, 연소성 류마티양 관절염, 골관절염(퇴행성 관절질환), 감기로 인한 발열 및 동통, 요통, 월경곤란증, 수술후 동통"],
85+ // image: null
86+ // },
87+ // {
88+ // id: 3,
89+ // name: "트라펜정",
90+ // category: "전문 의약품",
91+ // company: "명문제약(주) / Myungmoon Pharm",
92+ // effect: "트라마돌염산염,아세트아미노펜",
93+ // symptoms: ["중등도-중증의 급ㆍ만성 통증"],
94+ // image: null
95+ // },
96+ // ];
97+
98+ // // 검색어에 따른 결과 필터링 (임시로 "두통" 검색어만 결과 표시)
99+ // const searchResults = query?.toLowerCase() === "두통" ? mockResults : [];
100+
101+ // // 선택된 타입에 따라 결과 필터링
102+ // const filteredResults = selectedType === 'all'
103+ // ? fetchedResults
104+ // : fetchedResults.filter(medicine => {
105+ // if (selectedType === 'general') return medicine.category === "일반 의약품";
106+ // if (selectedType === 'prescription') return medicine.category === "전문 의약품";
107+ // return true;
108+ // });
109+
110+ // // 정렬 기준에 따라 결과 정렬
111+ // const sortedResults = [...filteredResults].sort((a, b) => {
112+ // switch (sortBy) {
113+ // case 'name':
114+ // return a.name.localeCompare(b.name, 'ko');
115+ // case 'effect':
116+ // return a.effect.localeCompare(b.effect, 'ko');
117+ // case 'company':
118+ // return a.company.localeCompare(b.company, 'ko');
119+ // default:
120+ // return 0;
121+ // }
122+ // });
123+
124+ // 검색 결과 수 업데이트
125+ // useEffect(() => {
126+ // setTotalResults(sortedResults.length);
127+ // }, [sortedResults.length]);
128+
129+ // // 드롭다운 외부 클릭 시 닫기
130+ // const handleClickOutside = () => {
131+ // setShowTypeDropdown(false);
132+ // setShowSortDropdown(false);
133+ // };
134+
135+ // const getTypeLabel = () => {
136+ // switch (selectedType) {
137+ // case 'all': return '전체';
138+ // case 'general': return '일반 의약품';
139+ // case 'prescription': return '전문 의약품';
140+ // default: return '전체';
141+ // }
142+ // };
143+
144+ // const getSortLabel = () => {
145+ // switch (sortBy) {
146+ // case 'name': return '제품명';
147+ // case 'effect': return '성분명';
148+ // case 'company': return '제약회사';
149+ // default: return '제품명';
150+ // }
151+ // };
152+
153+ // // 현재 필터 상태 텍스트 생성
154+ // const getFilterStatusText = () => {
155+ // const typeText = selectedType === 'all' ? '' : `${getTypeLabel()} · `;
156+ // const sortText = `${getSortLabel()} 순`;
157+ // return `${typeText}${sortText}`;
158+ // };
159+
160+ return (
161+ < div className = "min-h-screen flex flex-col bg-gray-50" >
162+ < Header />
163+ < main className = "flex-1 w-full mt-[64px]" >
164+ < div className = "max-w-7xl mx-auto w-full px-4" >
165+ { /* 검색창 영역 */ }
166+ < div className = "sticky top-[64px] bg-gray-50 z-10" >
167+ < SearchBar
168+ initialQuery = { query || '' }
169+ showTabs = { true }
170+ initialMode = "keyword"
171+ />
172+ </ div >
173+
174+ { /* 검색 결과 목록 */ }
175+ < div className = "space-y-4 mt-6" >
176+ { isLoading ? (
177+ < div className = "text-center py-16" > 로딩 중...</ div >
178+ ) : error ? (
179+ < div className = "text-center py-16 text-red-500" > 에러: { error } </ div >
180+ ) : fetchedResults . length > 0 ? (
181+ fetchedResults . map ( ( medicine ) => (
182+ < div
183+ key = { medicine . drugId }
184+ className = "bg-white rounded-lg shadow-sm p-4 border border-transparent hover:shadow-md hover:border-[#2BA89C] transition"
185+ // className="bg-white rounded-lg shadow-sm p-2 hover:shadow-md transition-shadow"
186+ >
187+ < div className = "flex divide-x divide-gray-200" >
188+ { /* <div className="flex items-start gap-4"> */ }
189+ { /* <div className="flex gap-4"> */ }
190+ < div className = "w-48 h-48 flex-shrink-0 pr-4" >
191+ { medicine . imageUrl ? (
192+ < img
193+ src = { medicine . imageUrl }
194+ alt = { medicine . drugName }
195+ className = "w-full h-full rounded-lg object-contain"
196+ />
197+ ) : (
198+ < NoImage />
199+ ) }
200+ </ div >
201+
202+ { /* 정보영역 */ }
203+ < div className = "flex-1 mt-11 pl-4 space-y-2 leading-relaxed" >
204+ { /* <div className="flex-1 mt-20 space-y-3 leading-relaxed"> */ }
205+ < p className = "text-base text-gray-600" > 명칭: { medicine . drugName } </ p >
206+ < p className = "text-base text-gray-600" > 제약회사: { medicine . company } </ p >
207+ < p className = "text-base text-gray-600" >
208+ 효능: { medicine . efficacy . join ( ', ' ) }
209+ </ p >
210+ </ div >
211+ </ div >
212+ </ div >
213+ ) )
214+ ) : (
215+ < div className = "text-center py-16" >
216+ < p className = "text-gray-500 mb-2" > 검색 결과가 없습니다.</ p >
217+ < p className = "text-sm text-gray-400" > 다른 검색어로 다시 시도해 보세요.</ p >
218+ </ div >
219+ ) }
220+ </ div >
221+
222+
223+
224+
225+ { /* 페이지네이션 */ }
226+ { fetchedResults . length > 0 && (
227+ < div className = "flex justify-center mt-8 gap-2" >
228+ { [ ...Array ( Math . ceil ( totalResults / itemsPerPage ) ) . keys ( ) ] . map ( i => (
229+ < button
230+ key = { i + 1 }
231+ onClick = { ( ) => setCurrentPage ( i + 1 ) }
232+ className = { `px-3 py-1 rounded ${
233+ i + 1 === currentPage
234+ ? 'bg-[#2BA89C] text-white'
235+ : 'bg-white text-gray-600 hover:bg-gray-100'
236+ } `}
237+ >
238+ { i + 1 }
239+ </ button >
240+ ) ) }
241+ </ div >
242+ ) }
243+ </ div >
244+ </ main >
245+ < Footer />
246+ </ div >
247+ ) ;
248+ } ;
249+
250+ // 메인 페이지 컴포넌트
251+ const SymptomSearchResults = ( ) => {
252+ return (
253+ < Suspense fallback = { < div > Loading...</ div > } >
254+ < SearchResults />
255+ </ Suspense >
256+ ) ;
257+ } ;
258+
259+ export default SymptomSearchResults ;
0 commit comments