From e6e07c617f2f2a6c44416302b6be6290b407ed9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=88=98=ED=98=81?= Date: Sun, 21 Jul 2024 19:59:50 +0900 Subject: [PATCH 1/9] =?UTF-8?q?FE-74=20fix:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20lodash=20=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 1 - package.json | 2 -- 2 files changed, 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index c2b1092c..1df42c85 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,6 @@ "axios": "^1.7.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", - "lodash": "^4.17.21", "lucide-react": "^0.407.0", "next": "14.2.4", "qs": "^6.12.2", diff --git a/package.json b/package.json index ba4aad72..fd2f3859 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "axios": "^1.7.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", - "lodash": "^4.17.21", "lucide-react": "^0.407.0", "next": "14.2.4", "qs": "^6.12.2", @@ -41,7 +40,6 @@ }, "devDependencies": { "@tanstack/eslint-plugin-query": "^5.50.0", - "@types/lodash": "^4.17.7", "@types/node": "^20.14.10", "@types/qs": "^6.9.15", "@types/react": "^18.3.3", From c6334b7be847b6ebf77b7a1692bc0f684a1f3bf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=88=98=ED=98=81?= Date: Wed, 24 Jul 2024 16:03:19 +0900 Subject: [PATCH 2/9] =?UTF-8?q?FE-74=20=E2=9C=A8feat:=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=9A=A9=20api=20=EC=BD=94=EB=93=9C=20=EA=B0=80?= =?UTF-8?q?=EC=A0=B8=EC=98=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/getEpigrams.ts | 12 ++++++++++++ src/schema/epigrams.ts | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 src/apis/getEpigrams.ts create mode 100644 src/schema/epigrams.ts diff --git a/src/apis/getEpigrams.ts b/src/apis/getEpigrams.ts new file mode 100644 index 00000000..9685bc60 --- /dev/null +++ b/src/apis/getEpigrams.ts @@ -0,0 +1,12 @@ +import { GetEpigramsParamsType, GetEpigramsResponseType, GetEpigramsResponse } from '@/schema/epigrams'; +import httpClient from '.'; + +const getEpigrams = async (params: GetEpigramsParamsType): Promise => { + const response = await httpClient.get(`/epigrams`, { params }); + + // 데이터 일치하는지 확인 + const parsedResponse = GetEpigramsResponse.parse(response.data); + return parsedResponse; +}; + +export default getEpigrams; diff --git a/src/schema/epigrams.ts b/src/schema/epigrams.ts new file mode 100644 index 00000000..46a7cb85 --- /dev/null +++ b/src/schema/epigrams.ts @@ -0,0 +1,33 @@ +import * as z from 'zod'; + +export const GetEpigramsParams = z.object({ + limit: z.number(), + cursor: z.number().optional(), + keyword: z.string().optional(), + writerId: z.number().optional(), +}); + +export const GetEpigramsResponse = z.object({ + totalCount: z.number(), + nextCursor: z.number(), + list: z.array( + z.object({ + likeCount: z.number(), + tags: z.array( + z.object({ + name: z.string(), + id: z.number(), + }), + ), + writerId: z.number(), + referenceUrl: z.string(), + referenceTitle: z.string(), + author: z.string(), + content: z.string(), + id: z.number(), + }), + ), +}); + +export type GetEpigramsParamsType = z.infer; +export type GetEpigramsResponseType = z.infer; From e141c2c82cc841e031ce450f3e8aa0c47dd47e8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=88=98=ED=98=81?= Date: Thu, 25 Jul 2024 15:49:50 +0900 Subject: [PATCH 3/9] =?UTF-8?q?FE-74=20=E2=9C=A8feat:=20=EA=B2=80=EC=83=89?= =?UTF-8?q?=20=EA=B2=B0=EA=B3=BC=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/search/SearchResults.tsx | 61 ++++++++++++++++---- src/pageLayout/SearchLayout/SearchLayout.tsx | 16 ++++- 2 files changed, 63 insertions(+), 14 deletions(-) diff --git a/src/components/search/SearchResults.tsx b/src/components/search/SearchResults.tsx index 08bb9e2f..e600fba4 100644 --- a/src/components/search/SearchResults.tsx +++ b/src/components/search/SearchResults.tsx @@ -1,17 +1,56 @@ import React from 'react'; +import Link from 'next/link'; + +interface Tag { + name: string; + id: number; +} + +interface Epigram { + likeCount: number; + tags: Tag[]; + id: number; + writerId: number; + referenceUrl: string; + referenceTitle: string; + author: string; + content: string; +} + +interface SearchResultsProps { + results: { + totalCount: number; + nextCursor: number; + list: Epigram[]; + } | null; +} + +function SearchResults({ results }: SearchResultsProps) { + if (!results) { + return
검색 결과가 없습니다.
; + } -function SearchResults() { return ( -
-
- 오랫동안 꿈을 그리는 사람은 마침내 그 꿈을 닮아 간다. - - 앙드레 말로 - -
-
- #동기부여 - #우울할때 - #나아가야할때 -
+ ); } diff --git a/src/pageLayout/SearchLayout/SearchLayout.tsx b/src/pageLayout/SearchLayout/SearchLayout.tsx index 2368d225..78be15d5 100644 --- a/src/pageLayout/SearchLayout/SearchLayout.tsx +++ b/src/pageLayout/SearchLayout/SearchLayout.tsx @@ -2,16 +2,18 @@ import React, { useState, useEffect } from 'react'; import SearchBar from '@/components/search/SearchBar'; import RecentSearches from '@/components/search/RecentSearches'; import SearchResults from '@/components/search/SearchResults'; +import { GetEpigramsResponseType } from '@/schema/epigrams'; +import getEpigrams from '@/apis/getEpigrams'; // TODO 로그인한 사용자에 따라서 최근 검색어를 관리할 수 있도록 추후에 수정 -// TODO api, SearchResults 컴포넌트와 연결 function SearchLayout() { const [searches, setSearches] = useState([]); const [currentSearch, setCurrentSearch] = useState(''); + const [results, setResults] = useState(null); // 검색어가 제출될 때 작동 - const handleSearch = (search: string) => { + const handleSearch = async (search: string) => { setSearches((prevSearches) => { // 중복되지 않는 검색어를 최근 검색어에 추가하고 최대 10개로 제한 const updatedSearches = [search, ...prevSearches.filter((item) => item !== search)].slice(0, 10); @@ -19,6 +21,14 @@ function SearchLayout() { return updatedSearches; }); setCurrentSearch(search); + + // API에서 데이터 가져오기 + try { + const response = await getEpigrams({ keyword: search, limit: 10 }); // TODO 후에 무한스크롤로 구현 + setResults(response); + } catch (error) { + setResults(null); + } }; // 모두지우기 클릭 시 저장된 최근 검색어 삭제 @@ -39,7 +49,7 @@ function SearchLayout() {
- +
); From 997e13df0b282274de9f44fa9c13a27cf6aeb20d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=88=98=ED=98=81?= Date: Thu, 25 Jul 2024 16:25:31 +0900 Subject: [PATCH 4/9] =?UTF-8?q?FE-74=20=E2=9C=A8fix:=20=EC=A4=91=EB=B3=B5?= =?UTF-8?q?=EB=90=9C=20key,=20href=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20?= =?UTF-8?q?=EA=B7=9C=EC=B9=99=20=EB=AC=B4=EC=8B=9C=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/search/SearchResults.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/search/SearchResults.tsx b/src/components/search/SearchResults.tsx index e600fba4..e56d5478 100644 --- a/src/components/search/SearchResults.tsx +++ b/src/components/search/SearchResults.tsx @@ -33,9 +33,10 @@ function SearchResults({ results }: SearchResultsProps) { return (
{results.list.map((item) => ( - - -
+ + {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} + +
{item.content} - {item.author} - From 1364ffae242196d4352ee3fceb672113bbc2053d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=88=98=ED=98=81?= Date: Thu, 25 Jul 2024 17:07:02 +0900 Subject: [PATCH 5/9] =?UTF-8?q?FE-74=20=E2=9C=A8test:=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/search/SearchResults.tsx | 54 +++++++++------ src/components/search/test.ts | 71 ++++++++++++++++++++ src/pageLayout/SearchLayout/SearchLayout.tsx | 5 +- src/pages/epigram/[id]/index.tsx | 41 +++++++++++ 4 files changed, 150 insertions(+), 21 deletions(-) create mode 100644 src/components/search/test.ts create mode 100644 src/pages/epigram/[id]/index.tsx diff --git a/src/components/search/SearchResults.tsx b/src/components/search/SearchResults.tsx index e56d5478..7ab6d8ac 100644 --- a/src/components/search/SearchResults.tsx +++ b/src/components/search/SearchResults.tsx @@ -23,33 +23,49 @@ interface SearchResultsProps { nextCursor: number; list: Epigram[]; } | null; + query: string; } -function SearchResults({ results }: SearchResultsProps) { +function SearchResults({ results, query }: SearchResultsProps) { if (!results) { - return
검색 결과가 없습니다.
; + return ( +
+
+ 검색 결과를 불러오는 중 문제가 발생했습니다. +
+
+ ); + } + + const filteredResults = results.list.filter((item) => item.content.includes(query) || item.author.includes(query) || item.tags.some((tag) => tag.name.includes(query))); + + if (filteredResults.length === 0) { + return ( +
+
+ 해당 검색어에 대한 결과가 없습니다. +
+
+ ); } return (
- {results.list.map((item) => ( - - {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} - - diff --git a/src/components/search/test.ts b/src/components/search/test.ts new file mode 100644 index 00000000..5e5cc0b9 --- /dev/null +++ b/src/components/search/test.ts @@ -0,0 +1,71 @@ +const testData = { + totalCount: 5, + nextCursor: 5, + list: [ + { + id: 1, + likeCount: 10, + tags: [ + { name: '동기부여', id: 101 }, + { name: '우울할때', id: 102 }, + { name: '나아가야할때', id: 103 }, + ], + writerId: 1001, + referenceUrl: 'https://example.com/epigram/1', + referenceTitle: 'The Power of Dreams', + author: '앙드레 말로', + content: '오랫동안 꿈을 그리는 사람은 마침내 그 꿈을 닮아 간다.', + }, + { + id: 2, + likeCount: 20, + tags: [{ name: '새로운영감', id: 201 }], + writerId: 1002, + referenceUrl: 'https://example.com/epigram/2', + referenceTitle: 'Life Lessons', + author: '파우울로 코엘료', + content: '이 세상에는 위대한 진실이 하나 있어. 무언가를 온 마음을 다해 원한다면, 반드시 그렇게 된다는거야.', + }, + { + id: 3, + likeCount: 15, + tags: [ + { name: '짧은명언', id: 301 }, + { name: '우울증', id: 302 }, + ], + writerId: 1003, + referenceUrl: 'https://example.com/epigram/3', + referenceTitle: 'Path to Success', + author: '클라우스 랑에', + content: '우울증이란 우리를 내적인 나락으로 이끄는 유혹의 손길이다.', + }, + { + id: 4, + likeCount: 5, + tags: [ + { name: 'motivation', id: 401 }, + { name: 'challenge', id: 402 }, + ], + writerId: 1004, + referenceUrl: 'https://example.com/epigram/4', + referenceTitle: 'Overcoming Challenges', + author: '테스터', + content: '우울한 기분은 신나는 기분을 더욱 더 신나게 만들어준다.', + }, + { + id: 5, + likeCount: 8, + tags: [ + { name: 'focus', id: 501 }, + { name: 'discipline', id: 502 }, + ], + writerId: 1005, + referenceUrl: 'https://example.com/epigram/5', + referenceTitle: 'Staying Focused', + author: 'David Wilson', + content: '그렇게 우울은 흘러가고 새로운 기분이 우릴 맞이할 것이다.', + }, + ], +}; + +export default testData; diff --git a/src/pageLayout/SearchLayout/SearchLayout.tsx b/src/pageLayout/SearchLayout/SearchLayout.tsx index 78be15d5..9ee215d3 100644 --- a/src/pageLayout/SearchLayout/SearchLayout.tsx +++ b/src/pageLayout/SearchLayout/SearchLayout.tsx @@ -4,13 +4,14 @@ import RecentSearches from '@/components/search/RecentSearches'; import SearchResults from '@/components/search/SearchResults'; import { GetEpigramsResponseType } from '@/schema/epigrams'; import getEpigrams from '@/apis/getEpigrams'; +import testData from '@/components/search/test'; // TODO 로그인한 사용자에 따라서 최근 검색어를 관리할 수 있도록 추후에 수정 function SearchLayout() { const [searches, setSearches] = useState([]); const [currentSearch, setCurrentSearch] = useState(''); - const [results, setResults] = useState(null); + const [, setResults] = useState(null); // 검색어가 제출될 때 작동 const handleSearch = async (search: string) => { @@ -49,7 +50,7 @@ function SearchLayout() {
- + {currentSearch && }
); diff --git a/src/pages/epigram/[id]/index.tsx b/src/pages/epigram/[id]/index.tsx new file mode 100644 index 00000000..6344f5a1 --- /dev/null +++ b/src/pages/epigram/[id]/index.tsx @@ -0,0 +1,41 @@ +// pages/epigrams/[id].tsx +import React from 'react'; +import { useRouter } from 'next/router'; +import testData from '@/components/search/test'; + +function EpigramDetail() { + const router = useRouter(); + const { id } = router.query; + + // `id`가 숫자인 경우를 대비하여 변환 + const epigramId = parseInt(id as string, 10); + const epigram = testData.list.find((e) => e.id === epigramId); + + if (!epigram) { + return
해당 에피그램을 찾을 수 없습니다.
; + } + + return ( +
+

에피그램 상세 페이지

+

{epigram.content}

+

작성자: {epigram.author}

+

+ 참조 제목:{' '} + + {epigram.referenceTitle} + +

+
+ 태그: + {epigram.tags.map((tag) => ( + + #{tag.name} + + ))} +
+
+ ); +} + +export default EpigramDetail; From f97a4e15b16cd171a5f23076ddf1cba76f8f3091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=88=98=ED=98=81?= Date: Thu, 25 Jul 2024 19:50:22 +0900 Subject: [PATCH 6/9] =?UTF-8?q?FE-74=20=E2=9C=A8feat:=20=EA=B2=80=EC=83=89?= =?UTF-8?q?=EC=96=B4=20=ED=95=98=EC=9D=B4=EB=9D=BC=EC=9D=B4=ED=8C=85=20?= =?UTF-8?q?=EB=B0=8F=20=EC=88=9C=EC=84=9C=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/search/SearchResults.tsx | 53 ++++++++++++++++---- src/components/search/test.ts | 8 +-- src/pageLayout/SearchLayout/SearchLayout.tsx | 2 + 3 files changed, 48 insertions(+), 15 deletions(-) diff --git a/src/components/search/SearchResults.tsx b/src/components/search/SearchResults.tsx index 7ab6d8ac..9007e00f 100644 --- a/src/components/search/SearchResults.tsx +++ b/src/components/search/SearchResults.tsx @@ -1,6 +1,8 @@ import React from 'react'; import Link from 'next/link'; +// TODO highlightedSections의 key 설정 부분에 더 나은 방법이 생각나면 변경 + interface Tag { name: string; id: number; @@ -26,18 +28,47 @@ interface SearchResultsProps { query: string; } +// 텍스트 하이라이팅 함수 +function handleHighlightText(text: string, highlight: string) { + if (!highlight.trim()) { + return text; + } + + // 검색어(highlight)기준으로 검색 결과를 배열로 나눔(g: 중복 O, i: 대소문자 구분 X) + const highlightedSections = text.split(new RegExp(`(${highlight})`, 'gi')); + + return ( + <> + {highlightedSections.map((section, index) => { + const key = `${section}-${index}-${section.length}`; + return section.toLowerCase() === highlight.toLowerCase() ? ( + + {section} + + ) : ( + section + ); + })} + + ); +} + function SearchResults({ results, query }: SearchResultsProps) { if (!results) { - return ( -
-
- 검색 결과를 불러오는 중 문제가 발생했습니다. -
-
- ); + return 검색 결과를 불러오는 중 문제가 발생했습니다.; } - const filteredResults = results.list.filter((item) => item.content.includes(query) || item.author.includes(query) || item.tags.some((tag) => tag.name.includes(query))); + // 태그와 내용 기준으로 정렬 + const sortedResults = results.list.sort((a, b) => { + const aHasTag = a.tags.some((tag) => tag.name.includes(query)); + const bHasTag = b.tags.some((tag) => tag.name.includes(query)); + + if (aHasTag && !bHasTag) return -1; + if (!aHasTag && bHasTag) return 1; + return 0; + }); + + const filteredResults = sortedResults.filter((item) => item.content.includes(query) || item.author.includes(query) || item.tags.some((tag) => tag.name.includes(query))); if (filteredResults.length === 0) { return ( @@ -55,13 +86,13 @@ function SearchResults({ results, query }: SearchResultsProps) {
- {item.content} - - {item.author} - + {handleHighlightText(item.content, query)} + - {handleHighlightText(item.author, query)} -
{item.tags.map((tag) => ( - #{tag.name} + {handleHighlightText(`#${tag.name}`, query)} ))}
diff --git a/src/components/search/test.ts b/src/components/search/test.ts index 5e5cc0b9..939c3b80 100644 --- a/src/components/search/test.ts +++ b/src/components/search/test.ts @@ -23,7 +23,7 @@ const testData = { writerId: 1002, referenceUrl: 'https://example.com/epigram/2', referenceTitle: 'Life Lessons', - author: '파우울로 코엘료', + author: '파우울로 코엘료 테스트', content: '이 세상에는 위대한 진실이 하나 있어. 무언가를 온 마음을 다해 원한다면, 반드시 그렇게 된다는거야.', }, { @@ -37,7 +37,7 @@ const testData = { referenceUrl: 'https://example.com/epigram/3', referenceTitle: 'Path to Success', author: '클라우스 랑에', - content: '우울증이란 우리를 내적인 나락으로 이끄는 유혹의 손길이다.', + content: '우울증이란 우리를 내적인 나락으로 이끄는 유혹의 손길이다. 테스트', }, { id: 4, @@ -49,14 +49,14 @@ const testData = { writerId: 1004, referenceUrl: 'https://example.com/epigram/4', referenceTitle: 'Overcoming Challenges', - author: '테스터', + author: '테스트터티', content: '우울한 기분은 신나는 기분을 더욱 더 신나게 만들어준다.', }, { id: 5, likeCount: 8, tags: [ - { name: 'focus', id: 501 }, + { name: '테스트', id: 501 }, { name: 'discipline', id: 502 }, ], writerId: 1005, diff --git a/src/pageLayout/SearchLayout/SearchLayout.tsx b/src/pageLayout/SearchLayout/SearchLayout.tsx index 9ee215d3..29315c9c 100644 --- a/src/pageLayout/SearchLayout/SearchLayout.tsx +++ b/src/pageLayout/SearchLayout/SearchLayout.tsx @@ -7,6 +7,8 @@ import getEpigrams from '@/apis/getEpigrams'; import testData from '@/components/search/test'; // TODO 로그인한 사용자에 따라서 최근 검색어를 관리할 수 있도록 추후에 수정 +// TODO 실제 api와 연동 +// TODO 검색 결과를 URL 에 저장, 새로고침시 데이터 분실에 대응 function SearchLayout() { const [searches, setSearches] = useState([]); From 515f6c38d52c67a6513beef4d9956e3a39ff502c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=88=98=ED=98=81?= Date: Thu, 25 Jul 2024 20:03:02 +0900 Subject: [PATCH 7/9] =?UTF-8?q?FE-74=20=E2=9C=A8fix:=20=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20api=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/getEpigrams.ts | 12 ---------- src/components/search/SearchResults.tsx | 23 ++------------------ src/pageLayout/SearchLayout/SearchLayout.tsx | 13 +---------- 3 files changed, 3 insertions(+), 45 deletions(-) delete mode 100644 src/apis/getEpigrams.ts diff --git a/src/apis/getEpigrams.ts b/src/apis/getEpigrams.ts deleted file mode 100644 index 9685bc60..00000000 --- a/src/apis/getEpigrams.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { GetEpigramsParamsType, GetEpigramsResponseType, GetEpigramsResponse } from '@/schema/epigrams'; -import httpClient from '.'; - -const getEpigrams = async (params: GetEpigramsParamsType): Promise => { - const response = await httpClient.get(`/epigrams`, { params }); - - // 데이터 일치하는지 확인 - const parsedResponse = GetEpigramsResponse.parse(response.data); - return parsedResponse; -}; - -export default getEpigrams; diff --git a/src/components/search/SearchResults.tsx b/src/components/search/SearchResults.tsx index 9007e00f..8124c082 100644 --- a/src/components/search/SearchResults.tsx +++ b/src/components/search/SearchResults.tsx @@ -1,30 +1,11 @@ import React from 'react'; import Link from 'next/link'; +import { GetEpigramsResponseType } from '@/schema/epigrams'; // TODO highlightedSections의 key 설정 부분에 더 나은 방법이 생각나면 변경 -interface Tag { - name: string; - id: number; -} - -interface Epigram { - likeCount: number; - tags: Tag[]; - id: number; - writerId: number; - referenceUrl: string; - referenceTitle: string; - author: string; - content: string; -} - interface SearchResultsProps { - results: { - totalCount: number; - nextCursor: number; - list: Epigram[]; - } | null; + results: GetEpigramsResponseType | null; query: string; } diff --git a/src/pageLayout/SearchLayout/SearchLayout.tsx b/src/pageLayout/SearchLayout/SearchLayout.tsx index 29315c9c..75b00aaa 100644 --- a/src/pageLayout/SearchLayout/SearchLayout.tsx +++ b/src/pageLayout/SearchLayout/SearchLayout.tsx @@ -2,18 +2,15 @@ import React, { useState, useEffect } from 'react'; import SearchBar from '@/components/search/SearchBar'; import RecentSearches from '@/components/search/RecentSearches'; import SearchResults from '@/components/search/SearchResults'; -import { GetEpigramsResponseType } from '@/schema/epigrams'; -import getEpigrams from '@/apis/getEpigrams'; import testData from '@/components/search/test'; // TODO 로그인한 사용자에 따라서 최근 검색어를 관리할 수 있도록 추후에 수정 -// TODO 실제 api와 연동 +// TODO 실제 api와 연동 후 테스트 코드 삭제 // TODO 검색 결과를 URL 에 저장, 새로고침시 데이터 분실에 대응 function SearchLayout() { const [searches, setSearches] = useState([]); const [currentSearch, setCurrentSearch] = useState(''); - const [, setResults] = useState(null); // 검색어가 제출될 때 작동 const handleSearch = async (search: string) => { @@ -24,14 +21,6 @@ function SearchLayout() { return updatedSearches; }); setCurrentSearch(search); - - // API에서 데이터 가져오기 - try { - const response = await getEpigrams({ keyword: search, limit: 10 }); // TODO 후에 무한스크롤로 구현 - setResults(response); - } catch (error) { - setResults(null); - } }; // 모두지우기 클릭 시 저장된 최근 검색어 삭제 From 763425418b8adf93bcc051778e5838511b3ef97b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=88=98=ED=98=81?= Date: Thu, 25 Jul 2024 20:06:26 +0900 Subject: [PATCH 8/9] =?UTF-8?q?FE-74=20=E2=9C=A8styles:=20=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/search/SearchResults.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/search/SearchResults.tsx b/src/components/search/SearchResults.tsx index 8124c082..d7943f02 100644 --- a/src/components/search/SearchResults.tsx +++ b/src/components/search/SearchResults.tsx @@ -18,6 +18,7 @@ function handleHighlightText(text: string, highlight: string) { // 검색어(highlight)기준으로 검색 결과를 배열로 나눔(g: 중복 O, i: 대소문자 구분 X) const highlightedSections = text.split(new RegExp(`(${highlight})`, 'gi')); + // 검색어와 비교해서 같으면 하이라이팅, 다르면 그냥 반환 return ( <> {highlightedSections.map((section, index) => { @@ -39,7 +40,7 @@ function SearchResults({ results, query }: SearchResultsProps) { return 검색 결과를 불러오는 중 문제가 발생했습니다.; } - // 태그와 내용 기준으로 정렬 + // 태그와 내용 순서로 정렬 const sortedResults = results.list.sort((a, b) => { const aHasTag = a.tags.some((tag) => tag.name.includes(query)); const bHasTag = b.tags.some((tag) => tag.name.includes(query)); From 0dbd7cbaa55e266706c9c0264168415792f27486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=88=98=ED=98=81?= Date: Fri, 26 Jul 2024 16:58:05 +0900 Subject: [PATCH 9/9] =?UTF-8?q?FE-74=20=E2=9C=A8fix:=20=EB=A9=98=ED=86=A0?= =?UTF-8?q?=EB=A7=81=20=20=EB=82=B4=EC=9A=A9=20=EC=A3=BC=EC=84=9D=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/search/SearchBar.tsx | 2 ++ src/components/search/SearchResults.tsx | 1 + 2 files changed, 3 insertions(+) diff --git a/src/components/search/SearchBar.tsx b/src/components/search/SearchBar.tsx index ae50acf5..accf11f1 100644 --- a/src/components/search/SearchBar.tsx +++ b/src/components/search/SearchBar.tsx @@ -2,6 +2,8 @@ import React, { useState, useEffect } from 'react'; import Image from 'next/image'; import SEARCH_ICON from '../../../public/md.svg'; +// TODO react-hook-form 사용 + interface SearchBarProps { onSearch: (search: string) => void; currentSearch: string; diff --git a/src/components/search/SearchResults.tsx b/src/components/search/SearchResults.tsx index d7943f02..413f9c90 100644 --- a/src/components/search/SearchResults.tsx +++ b/src/components/search/SearchResults.tsx @@ -50,6 +50,7 @@ function SearchResults({ results, query }: SearchResultsProps) { return 0; }); + // TODO useMemo 사용하는게 나을 것 같음(멘토님) const filteredResults = sortedResults.filter((item) => item.content.includes(query) || item.author.includes(query) || item.tags.some((tag) => tag.name.includes(query))); if (filteredResults.length === 0) {