-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
19 changed files
with
335 additions
and
18 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
export default function SearchLayout({ | ||
children | ||
}: Readonly<{ | ||
children: React.ReactNode; | ||
}>) { | ||
return ( | ||
<div className="bg-bg w-full"> | ||
<div className=" max-w-[600px] h-full min-h-screen w-full mx-auto">{children}</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import SearchIndex from '@/components/search/SearchIndex'; | ||
import React from 'react'; | ||
|
||
const SearchPage = () => { | ||
return <SearchIndex />; | ||
}; | ||
|
||
export default SearchPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
'use client'; | ||
import React, { ChangeEvent, useCallback, useRef, useState } from 'react'; | ||
import SearchRank from './SearchRank'; | ||
import useDebounce from '@/hook/useDebounce'; | ||
import { getSearchItem } from '@/factory/SearchItem'; | ||
import CircleSkeleton from '../skeleton/CircleSkeleton'; | ||
import SearchedResultItem from './SearchedResultItem'; | ||
import { useSearchStore } from '@/store/search.store'; | ||
|
||
const SearchIndex = () => { | ||
const { currentKeyword } = useSearchStore(); | ||
const [isFocused, setIsFocused] = useState(false); | ||
const [keyWord, setKeyWord] = useState(currentKeyword); // 전역 currentKeyword가 존재한다면 우선사용 | ||
const inputRef = useRef<HTMLInputElement>(null); | ||
const debouncedKeyword = useDebounce(keyWord); | ||
|
||
const { data, isLoading } = getSearchItem(debouncedKeyword); | ||
|
||
const handleKeyword = useCallback((e: ChangeEvent<HTMLInputElement>) => { | ||
setKeyWord(e.target.value); | ||
}, []); | ||
|
||
const handleClear = useCallback(() => { | ||
setKeyWord(''); | ||
if (inputRef.current) { | ||
inputRef.current.focus(); | ||
} | ||
}, []); | ||
|
||
return ( | ||
<div className="pt-10 flex flex-col gap-10"> | ||
{keyWord ? null : ( | ||
<div className="text-heading1 text-gray700 flex items-center justify-center"> | ||
찾으시는 상품이 있으신가요? | ||
</div> | ||
)} | ||
|
||
<div className="flex items-center justify-center"> | ||
<div | ||
className={`max-w-[520px] w-full bg-white flex items-center justify-center py-[14px] px-4 rounded-[12px] | ||
${isFocused || keyWord ? 'border-[1.5px] border-normal' : 'border-[1.5px] border-gray100'} | ||
`}> | ||
<input | ||
ref={inputRef} | ||
onFocus={() => setIsFocused(true)} | ||
onBlur={() => setIsFocused(false)} | ||
value={keyWord} | ||
onChange={handleKeyword} | ||
type="text" | ||
placeholder="조각투자 상품 검색" | ||
className="w-full outline-none text-body2 " | ||
/> | ||
{keyWord && ( | ||
<div onClick={handleClear} className="cursor-pointer mr-3"> | ||
<img src="/images/search/xcircle.svg" alt="" /> | ||
</div> | ||
)} | ||
<div> | ||
<img src="/images/search/search_icon.svg" alt="" /> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
{keyWord ? null : ( | ||
<div> | ||
<div className="text-heading3 text-gray700">실시간 검색</div> | ||
<SearchRank setKeyWord={setKeyWord} /> | ||
</div> | ||
)} | ||
|
||
{keyWord && isLoading && <CircleSkeleton />} | ||
{keyWord && !isLoading && data && ( | ||
<div> | ||
<div className="text-heading2"> | ||
<span className="text-gray700">검색 결과</span>{' '} | ||
<span className="text-normal">{data?.length}개</span> | ||
</div> | ||
<ul className="mt-10 pb-10 flex flex-col gap-4"> | ||
{data?.map((item, i) => <SearchedResultItem key={i} {...item} />)} | ||
</ul> | ||
</div> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
export default SearchIndex; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
'use client'; | ||
import { getRealtimeRank } from '@/factory/RealtimeRank'; | ||
import React, { Dispatch } from 'react'; | ||
import RealtimeRankSkeleton from '../skeleton/RealtimeSkeleton'; | ||
import { RealtimeRankType } from '@/types/homeComponentsType'; | ||
import SearchRankSkeleton from '../skeleton/SearchRankSkeleton'; | ||
|
||
interface SearchRankType { | ||
setKeyWord: Dispatch<React.SetStateAction<string>>; | ||
} | ||
|
||
const SearchRank = ({ setKeyWord }: SearchRankType) => { | ||
const { data, isLoading } = getRealtimeRank(); | ||
|
||
const handleClick = (keyword: string) => { | ||
setKeyWord(keyword); | ||
}; | ||
|
||
if (isLoading) { | ||
return <SearchRankSkeleton />; | ||
} | ||
|
||
return ( | ||
<div className="mt-3 w-full h-[291px]"> | ||
<div className="p-5 shadow-custom-normal rounded-[12px] flex-1 bg-white"> | ||
<ul className="flex flex-col gap-5"> | ||
{data?.map((item: RealtimeRankType, i: number) => ( | ||
<li key={i} className="flex gap-3 items-center"> | ||
<div | ||
className={`${i < 3 ? 'text-normal text-body6 ' : 'text-gray400 text-body6'}`}> | ||
{item.rank}위 | ||
</div> | ||
<div className="flex-1 text-body2 text-black truncate">{item.keyword}</div> | ||
{/* todo : 돋보기 누르면 그대로 검색 쿼리에 keyword가 들어가게하기 */} | ||
<div className="w-6 h-6 rounded-full bg-gray100 flex items-center justify-center cursor-pointer"> | ||
<img | ||
onClick={() => handleClick(item.keyword)} | ||
src="/images/home/search.svg" | ||
alt="search" | ||
/> | ||
</div> | ||
</li> | ||
))} | ||
</ul> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default SearchRank; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import type { SearchedItem } from '@/types/homeComponentsType'; | ||
|
||
import { formatCategory } from '@/utils/formatCategory'; | ||
import { useRouter } from 'next/navigation'; | ||
import React from 'react'; | ||
|
||
const SearchedResultItem = ({ productId, name, platform, category }: SearchedItem) => { | ||
const router = useRouter(); | ||
|
||
return ( | ||
<li | ||
onClick={() => router.push(`/product/detail/${productId}`)} | ||
className="p-5 cursor-pointer bg-white rounded-[12px]"> | ||
<div className="flex gap-5 items-center"> | ||
{/* 이미지 */} | ||
<div> | ||
<img | ||
src={'/images/home/mock.jpeg'} | ||
alt="" | ||
className="w-[82px] h-[82px] rounded-[8px]" | ||
/> | ||
</div> | ||
{/* 메인정보 */} | ||
<div className="flex-1 flex flex-col gap-[10px]"> | ||
<div className="flex items-center gap-2"> | ||
<div className="text-caption3 text-gray400 p-[6px] bg-bg rounded-[4px] flex items-center justify-center"> | ||
{formatCategory(category)} | ||
</div> | ||
<div className="text-body7 text-gray300 ">{platform}</div> | ||
</div> | ||
<div className="text-body1">{name}</div> | ||
</div> | ||
{/* 부가정보 */} | ||
<div className="flex items-center gap-4"> | ||
<div className="cursor-pointer"> | ||
<img src="/images/home/bookmark.svg" alt="" /> | ||
</div> | ||
</div> | ||
</div> | ||
</li> | ||
); | ||
}; | ||
|
||
export default SearchedResultItem; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export default function CircleSkeleton({ className = '' }) { | ||
return ( | ||
<div className="fixed inset-0 flex items-center justify-center z-[99999]"> | ||
<div className="h-16 w-16 animate-spin rounded-full border-8 border-t-normal border-gray-300" /> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import React from 'react'; | ||
|
||
const SearchRankSkeleton = () => { | ||
return ( | ||
<div className="mt-3 w-full h-[291px] hidden desk2:block"> | ||
<div className="flex flex-col gap-5 animate-pulse"> | ||
<div className="p-5 shadow-custom-normal rounded-[12px] flex-1"> | ||
<ul className="flex flex-col gap-5"> | ||
{Array.from({ length: 5 }).map((_, i) => ( | ||
<li key={i} className="flex gap-3 items-center"> | ||
<div className={`w-8 h-4 bg-gray-300 rounded-md`} /> | ||
<div className="flex-1 h-4 bg-gray-300 rounded-md" /> | ||
<div className="w-6 h-6 bg-gray-200 rounded-full" /> | ||
</li> | ||
))} | ||
</ul> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default SearchRankSkeleton; |
Oops, something went wrong.