From 9fe97bede582dd7c7192b7a166b42f6822fe741d Mon Sep 17 00:00:00 2001 From: Seo San Date: Wed, 4 Dec 2024 22:46:34 +0900 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20=EC=98=81=EC=96=B4=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=EC=8B=9C=20=ED=95=9C=EA=B8=80=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=ED=99=98=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=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 --- FE/package-lock.json | 7 ++++ FE/package.json | 1 + FE/src/components/Search/KoreanMapping.ts | 50 +++++++++++++++++++++++ FE/src/components/Search/index.tsx | 35 +++++++++++++++- 4 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 FE/src/components/Search/KoreanMapping.ts diff --git a/FE/package-lock.json b/FE/package-lock.json index 762e3fb..27b337a 100644 --- a/FE/package-lock.json +++ b/FE/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@heroicons/react": "^2.1.5", "@tanstack/react-query": "^4.36.1", + "hangul-js": "^0.2.6", "lottie-react": "^2.4.0", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -2571,6 +2572,12 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "node_modules/hangul-js": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/hangul-js/-/hangul-js-0.2.6.tgz", + "integrity": "sha512-48axU8LgjCD30FEs66Xc04/8knxMwCMQw0f67l67rlttW7VXT3qRJgQeHmhiuGwWXGvSbk6YM0fhQlcjE1JFQA==", + "license": "MIT" + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", diff --git a/FE/package.json b/FE/package.json index 683aacf..a25e8b5 100644 --- a/FE/package.json +++ b/FE/package.json @@ -12,6 +12,7 @@ "dependencies": { "@heroicons/react": "^2.1.5", "@tanstack/react-query": "^4.36.1", + "hangul-js": "^0.2.6", "lottie-react": "^2.4.0", "react": "^18.3.1", "react-dom": "^18.3.1", diff --git a/FE/src/components/Search/KoreanMapping.ts b/FE/src/components/Search/KoreanMapping.ts new file mode 100644 index 0000000..5e0ab2e --- /dev/null +++ b/FE/src/components/Search/KoreanMapping.ts @@ -0,0 +1,50 @@ +type CharacterMap = { + [key: string]: string; +}; + +export class SimpleKoreanConverter { + private charMap: CharacterMap; + + constructor() { + this.charMap = { + r: 'ㄱ', + R: 'ㄲ', + s: 'ㄴ', + e: 'ㄷ', + E: 'ㄸ', + f: 'ㄹ', + a: 'ㅁ', + q: 'ㅂ', + Q: 'ㅃ', + t: 'ㅅ', + T: 'ㅆ', + d: 'ㅇ', + w: 'ㅈ', + W: 'ㅉ', + c: 'ㅊ', + z: 'ㅋ', + x: 'ㅌ', + v: 'ㅍ', + g: 'ㅎ', + + k: 'ㅏ', + o: 'ㅐ', + i: 'ㅑ', + O: 'ㅒ', + j: 'ㅓ', + p: 'ㅔ', + u: 'ㅕ', + P: 'ㅖ', + h: 'ㅗ', + y: 'ㅛ', + n: 'ㅜ', + b: 'ㅠ', + m: 'ㅡ', + l: 'ㅣ', + }; + } + + public convert(input: string): string[] { + return Array.from(input).map((char) => this.charMap[char] || char); + } +} diff --git a/FE/src/components/Search/index.tsx b/FE/src/components/Search/index.tsx index 5a84c32..1b0f52f 100644 --- a/FE/src/components/Search/index.tsx +++ b/FE/src/components/Search/index.tsx @@ -12,6 +12,8 @@ import searchAnimation from 'assets/searchAnimation.json'; import { useSearchHistory } from 'hooks/useSearchHistoryHook.ts'; import { getSearchResults } from 'service/search.ts'; import { formatNoSpecialChar } from 'utils/format.ts'; +import { SimpleKoreanConverter } from './KoreanMapping.ts'; +import * as Hangul from 'hangul-js'; export default function SearchModal() { const { isOpen, toggleSearchModal } = useSearchModalStore(); @@ -19,18 +21,48 @@ export default function SearchModal() { const { searchHistory, addSearchHistory, deleteSearchHistory } = useSearchHistory(); const shouldSearch = searchInput.trim().length >= 2; + const converter = new SimpleKoreanConverter(); const { debounceValue, isDebouncing } = useDebounce( shouldSearch ? searchInput : '', 500, ); - const { data, isLoading, isFetching } = useQuery({ + + const { + data: originalData, + isLoading: isOriginalLoading, + isFetching: isOriginalFetching, + } = useQuery({ queryKey: ['search', debounceValue], queryFn: () => getSearchResults(formatNoSpecialChar(debounceValue)), enabled: !!debounceValue && !isDebouncing, staleTime: 1000, cacheTime: 1000 * 60, }); + const convertedSearch = debounceValue + ? Hangul.assemble(converter.convert(debounceValue)) + : ''; + + const { + data: convertedData, + isLoading: isConvertedLoading, + isFetching: isConvertedFetching, + } = useQuery({ + queryKey: ['search', convertedSearch], + queryFn: () => getSearchResults(formatNoSpecialChar(convertedSearch)), + enabled: + !isOriginalLoading && + !isOriginalFetching && + !!convertedSearch && + originalData !== undefined && + originalData.length === 0, + staleTime: 1000, + cacheTime: 1000 * 60, + }); + + const data = originalData?.length ? originalData : convertedData || []; + const isLoading = isOriginalLoading || isConvertedLoading; + const isFetching = isOriginalFetching || isConvertedFetching; useEffect(() => { if (data && data.length > 0 && debounceValue && !isLoading) { @@ -56,7 +88,6 @@ export default function SearchModal() {
- {' '} {!searchInput ? (