@@ -7,7 +7,10 @@ import { Header } from "@/components/common/Header";
77import { NewCategoryBottomSheet } from "@/components/study/NewCategoryBottomSheet" ;
88import { TermDescriptionCard } from "@/components/study/TermDescriptionCard" ;
99import { getNewsDetail , type NewsDetail , type CoreTerm } from "@/lib/api/news" ;
10- import { saveNewsToStorage , getStorageFoldersByItemId } from "@/lib/api/storage" ;
10+ import {
11+ saveNewsToStorage ,
12+ getStorageFoldersByItemId ,
13+ } from "@/lib/api/storage" ;
1114
1215type Category = {
1316 category_id : number ;
@@ -50,7 +53,7 @@ export default function NewsDetailPage() {
5053 setLoading ( true ) ;
5154 const data = await getNewsDetail ( newsId ) ;
5255 setNews ( data . data ) ;
53-
56+
5457 // 뉴스 상세 조회 후 저장된 폴더 목록도 조회
5558 const articleId = parseInt ( newsId , 10 ) ;
5659 if ( ! isNaN ( articleId ) ) {
@@ -99,7 +102,6 @@ export default function NewsDetailPage() {
99102 }
100103 } ;
101104
102-
103105 const handleAddNewCategory = ( ) => {
104106 // TODO: 새 카테고리 추가 기능 구현
105107 console . log ( "새 카테고리 추가" ) ;
@@ -114,7 +116,7 @@ export default function NewsDetailPage() {
114116
115117 const handleSolveProblems = ( ) => {
116118 // 퀴즈 옵션 페이지로 이동 (newsId를 naverArticleId로 사용)
117- router . push ( `/quiz?naverArticleId= ${ newsId } ` ) ;
119+ router . push ( `/quiz/ ${ newsId } ` ) ;
118120 } ;
119121
120122 // 핵심 단어를 하이라이트하는 함수 (각 단어는 첫 번째 매칭만 하이라이트)
@@ -125,7 +127,12 @@ export default function NewsDetailPage() {
125127 }
126128
127129 // 각 coreTerm별로 첫 번째 매칭만 찾기
128- const matches : Array < { start : number ; end : number ; coreTerm : CoreTerm ; term : string } > = [ ] ;
130+ const matches : Array < {
131+ start : number ;
132+ end : number ;
133+ coreTerm : CoreTerm ;
134+ term : string ;
135+ } > = [ ] ;
129136 const usedTerms = new Set < string > ( ) ;
130137
131138 news . coreTerms . forEach ( ( coreTerm ) => {
@@ -152,9 +159,9 @@ export default function NewsDetailPage() {
152159 . sort ( ( a , b ) => b . end - b . start - ( a . end - a . start ) ) // 긴 단어 우선
153160 . filter ( ( match , index , arr ) => {
154161 // 겹치지 않는 것만 선택
155- return ! arr . slice ( 0 , index ) . some (
156- ( m ) => ! ( match . end <= m . start || match . start >= m . end )
157- ) ;
162+ return ! arr
163+ . slice ( 0 , index )
164+ . some ( ( m ) => ! ( match . end <= m . start || match . start >= m . end ) ) ;
158165 } )
159166 . sort ( ( a , b ) => a . start - b . start ) ; // 인덱스 순서대로 정렬
160167
@@ -180,7 +187,7 @@ export default function NewsDetailPage() {
180187 cursor-pointer"
181188 >
182189 { match . term }
183- </ span >
190+ </ span > ,
184191 ) ;
185192 lastIndex = match . end ;
186193 } ) ;
@@ -299,7 +306,9 @@ export default function NewsDetailPage() {
299306 viewBox = "0 0 24 24"
300307 fill = "none"
301308 xmlns = "http://www.w3.org/2000/svg"
302- className = { isSaved ? "text-primary-30 fill-primary-30" : "text-white" }
309+ className = {
310+ isSaved ? "text-primary-30 fill-primary-30" : "text-white"
311+ }
303312 >
304313 < path
305314 d = "M5 5C5 3.89543 5.89543 3 7 3H17C18.1046 3 19 3.89543 19 5V21L12 17L5 21V5Z"
@@ -315,122 +324,125 @@ export default function NewsDetailPage() {
315324 />
316325
317326 < div className = "flex-1 px-5" >
318- < div className = "flex flex-col items-start gap-5" >
319- { /* 태그 */ }
320- { news . coreTerms && news . coreTerms . length > 0 && (
321- < div className = "flex items-center gap-[5px]" >
322- { news . coreTerms . map ( ( coreTerm , index ) => (
323- < span
324- key = { coreTerm . termId || index }
325- className = "flex items-center justify-center gap-[10px] px-[12px] py-[5px] rounded-[16px] border border-primary-70 bg-primary-80 text-b4 text-gray-20"
326- >
327- #{ coreTerm . term }
328- </ span >
329- ) ) }
330- </ div >
331- ) }
332-
333- { /* 제목과 발행일시 */ }
334- < div className = "flex flex-col items-start gap-[10px] self-stretch" >
335- < h1 className = "text-h2 text-gray-10" > { news . title } </ h1 >
336- < p className = "text-b3 text-gray-40" > { news . date } </ p >
327+ < div className = "flex flex-col items-start gap-5" >
328+ { /* 태그 */ }
329+ { news . coreTerms && news . coreTerms . length > 0 && (
330+ < div className = "flex items-center gap-[5px]" >
331+ { news . coreTerms . map ( ( coreTerm , index ) => (
332+ < span
333+ key = { coreTerm . termId || index }
334+ className = "flex items-center justify-center gap-[10px] px-[12px] py-[5px] rounded-[16px] border border-primary-70 bg-primary-80 text-b4 text-gray-20"
335+ >
336+ #{ coreTerm . term }
337+ </ span >
338+ ) ) }
337339 </ div >
340+ ) }
341+
342+ { /* 제목과 발행일시 */ }
343+ < div className = "flex flex-col items-start gap-[10px] self-stretch" >
344+ < h1 className = "text-h2 text-gray-10" > { news . title } </ h1 >
345+ < p className = "text-b3 text-gray-40" > { news . date } </ p >
346+ </ div >
347+ </ div >
348+
349+ { /* 썸네일 이미지 */ }
350+ { news . thumbnailUrl && (
351+ < div className = "w-full flex justify-center mt-5 mb-5" >
352+ < img
353+ src = { news . thumbnailUrl }
354+ alt = { news . title }
355+ className = "max-w-full h-auto object-contain rounded-lg"
356+ />
338357 </ div >
358+ ) }
339359
340- { /* 썸네일 이미지 */ }
341- { news . thumbnailUrl && (
342- < div className = "w-full flex justify-center mt-5 mb-5" >
360+ { /* AI 핵심 요약 */ }
361+ { news . summary3Lines && (
362+ < div className = "gap-[10px]" >
363+ < div className = "inline-flex h-[25px] pt-[1px] justify-center items-center gap-[10px] mb-4" >
343364 < img
344- src = { news . thumbnailUrl }
345- alt = { news . title }
346- className = "max-w-full h-auto object-contain rounded-lg"
365+ src = "/study/img-light.png"
366+ alt = "AI 핵심 요약"
367+ className = "h-full w-auto"
368+ width = { 15 }
369+ height = { 24 }
347370 />
371+ < h2 className = "text-sh5 text-gray-20" > AI 핵심 요약</ h2 >
348372 </ div >
349- ) }
350-
351- { /* AI 핵심 요약 */ }
352- { news . summary3Lines && (
353- < div className = "gap-[10px]" >
354- < div className = "inline-flex h-[25px] pt-[1px] justify-center items-center gap-[10px] mb-4" >
355- < img
356- src = "/study/img-light.png"
357- alt = "AI 핵심 요약"
358- className = "h-full w-auto"
359- width = { 15 }
360- height = { 24 }
361- />
362- < h2 className = "text-sh5 text-gray-20" > AI 핵심 요약</ h2 >
363- </ div >
364- < div className = "flex flex-col items-start gap-[10px] px-5 py-6 rounded-[8px] bg-bg-80" >
365- { summaryLines . map ( ( line , index ) => (
366- < div key = { index } className = "flex items-start gap-2 text-b2 text-gray-20" >
367- < span className = "flex-shrink-0" > •</ span >
368- < span > { line } </ span >
369- </ div >
370- ) ) }
371- </ div >
372- </ div >
373- ) }
374-
375- { /* 본문 내용 */ }
376- { news . bodySummary && (
377- < div className = "flex flex-col items-center justify-center w-full px-5 py-6 mt-[25px] mb-[25px] gap-[10px] rounded-[8px] bg-bg-90" >
378- < div className = "text-b2 text-gray-20 whitespace-pre-line" >
379- { highlightCoreTerms ( news . bodySummary ) }
380- </ div >
381- </ div >
382- ) }
383-
384- { /* 핵심 인사이트 */ }
385- { news . insights && news . insights . length > 0 && (
386- < div className = "gap-[10px]" >
387- < div className = "inline-flex pt-[1px] justify-center items-center gap-[10px]" >
388- < img
389- src = "/study/img-insight.png"
390- alt = "핵심 인사이트"
391- className = "h-full w-auto"
392- width = { 23 }
393- height = { 26 }
394- />
395- < h2 className = "text-sh5 text-gray-20" > 핵심 인사이트</ h2 >
396- </ div >
397- { news . insights . map ( ( insight , index ) => (
373+ < div className = "flex flex-col items-start gap-[10px] px-5 py-6 rounded-[8px] bg-bg-80" >
374+ { summaryLines . map ( ( line , index ) => (
398375 < div
399376 key = { index }
400- className = "flex flex-col items-start gap-[10px] px-5 py-6 rounded-[8px] bg-bg-90 mb-4 "
377+ className = "flex items-start gap-2 text-b2 text-gray-20 "
401378 >
402- { insight . title && (
403- < h3 className = "text-b1 text-gray-10 font-semibold" >
404- { insight . title }
405- </ h3 >
406- ) }
407- { insight . detail && (
408- < p className = "text-b2 text-gray-20" > { insight . detail } </ p >
409- ) }
410- { insight . whyItMatters && (
411- < p className = "text-b3 text-gray-30" >
412- < span className = "font-semibold" > 왜 중요한가:</ span > { " " }
413- { insight . whyItMatters }
414- </ p >
415- ) }
379+ < span className = "flex-shrink-0" > •</ span >
380+ < span > { line } </ span >
416381 </ div >
417382 ) ) }
418383 </ div >
419- ) }
384+ </ div >
385+ ) }
420386
421- { /* 하단 버튼들 */ }
422- < button
423- onClick = { handleViewOriginal }
424- className = "flex-1 w-full px-[10px] py-2 justify-center items-center gap-[10px] mt-5 mb-5 rounded-[8px] bg-bg-90 text-b2 text-gray-40"
425- >
426- 원문 보러가기
427- </ button >
428- < button
429- onClick = { handleSolveProblems }
430- className = "flex-1 w-full justify-center items-center px-4 py-[18px] rounded-[12px] bg-primary-50 text-b1 text-gray-10 text-center"
431- >
432- 문제 풀러가기
433- </ button >
387+ { /* 본문 내용 */ }
388+ { news . bodySummary && (
389+ < div className = "flex flex-col items-center justify-center w-full px-5 py-6 mt-[25px] mb-[25px] gap-[10px] rounded-[8px] bg-bg-90" >
390+ < div className = "text-b2 text-gray-20 whitespace-pre-line" >
391+ { highlightCoreTerms ( news . bodySummary ) }
392+ </ div >
393+ </ div >
394+ ) }
395+
396+ { /* 핵심 인사이트 */ }
397+ { news . insights && news . insights . length > 0 && (
398+ < div className = "gap-[10px]" >
399+ < div className = "inline-flex pt-[1px] justify-center items-center gap-[10px]" >
400+ < img
401+ src = "/study/img-insight.png"
402+ alt = "핵심 인사이트"
403+ className = "h-full w-auto"
404+ width = { 23 }
405+ height = { 26 }
406+ />
407+ < h2 className = "text-sh5 text-gray-20" > 핵심 인사이트</ h2 >
408+ </ div >
409+ { news . insights . map ( ( insight , index ) => (
410+ < div
411+ key = { index }
412+ className = "flex flex-col items-start gap-[10px] px-5 py-6 rounded-[8px] bg-bg-90 mb-4"
413+ >
414+ { insight . title && (
415+ < h3 className = "text-b1 text-gray-10 font-semibold" >
416+ { insight . title }
417+ </ h3 >
418+ ) }
419+ { insight . detail && (
420+ < p className = "text-b2 text-gray-20" > { insight . detail } </ p >
421+ ) }
422+ { insight . whyItMatters && (
423+ < p className = "text-b3 text-gray-30" >
424+ < span className = "font-semibold" > 왜 중요한가:</ span > { " " }
425+ { insight . whyItMatters }
426+ </ p >
427+ ) }
428+ </ div >
429+ ) ) }
430+ </ div >
431+ ) }
432+
433+ { /* 하단 버튼들 */ }
434+ < button
435+ onClick = { handleViewOriginal }
436+ className = "flex-1 w-full px-[10px] py-2 justify-center items-center gap-[10px] mt-5 mb-5 rounded-[8px] bg-bg-90 text-b2 text-gray-40"
437+ >
438+ 원문 보러가기
439+ </ button >
440+ < button
441+ onClick = { handleSolveProblems }
442+ className = "flex-1 w-full justify-center items-center px-4 py-[18px] rounded-[12px] bg-primary-50 text-b1 text-gray-10 text-center"
443+ >
444+ 문제 풀러가기
445+ </ button >
434446 </ div >
435447
436448 { /* 보관함 저장 바텀시트 */ }
@@ -452,4 +464,3 @@ export default function NewsDetailPage() {
452464 </ div >
453465 ) ;
454466}
455-
0 commit comments