- 중간부분에 처리할수없는 부분이있어 주석처리해두었습니다. - 주석명 (검색내용이 존재하고, 인풋창에 포커스가 가서 노출 시작) - 나머지 디자인 맞춰서 작업해두었습니다. - 데이터 다른데서 가져와서 넣어두었습니다.
817 lines
26 KiB
JavaScript
817 lines
26 KiB
JavaScript
// src/views/SearchPanel/SearchPanel.new.jsx
|
|
import React, {
|
|
useCallback,
|
|
useEffect,
|
|
useMemo,
|
|
useRef,
|
|
useState,
|
|
} from 'react';
|
|
|
|
import classNames from 'classnames';
|
|
import {
|
|
useDispatch,
|
|
useSelector,
|
|
} from 'react-redux';
|
|
|
|
import { Job } from '@enact/core/util';
|
|
import Spotlight from '@enact/spotlight';
|
|
import SpotlightContainerDecorator
|
|
from '@enact/spotlight/SpotlightContainerDecorator';
|
|
import Spottable from '@enact/spotlight/Spottable';
|
|
import { setContainerLastFocusedElement } from '@enact/spotlight/src/container';
|
|
|
|
import micIcon from '../../../assets/images/searchpanel/image-mic.png';
|
|
import hotPicksImage from '../../../assets/images/searchpanel/img-hotpicks.png';
|
|
import hotPicksBrandImage
|
|
from '../../../assets/images/searchpanel/img-search-hotpicks.png';
|
|
import {
|
|
sendLogGNB,
|
|
sendLogTotalRecommend,
|
|
} from '../../actions/logActions';
|
|
import { getMyRecommandedKeyword } from '../../actions/myPageActions';
|
|
import {
|
|
popPanel,
|
|
updatePanel,
|
|
} from '../../actions/panelActions';
|
|
import {
|
|
getSearch,
|
|
resetSearch,
|
|
} from '../../actions/searchActions';
|
|
import {
|
|
showErrorToast,
|
|
showInfoToast,
|
|
showSearchErrorToast,
|
|
showSearchSuccessToast,
|
|
showSuccessToast,
|
|
showWarningToast,
|
|
} from '../../actions/toastActions';
|
|
import TBody from '../../components/TBody/TBody';
|
|
import TInput, {
|
|
ICONS,
|
|
KINDS,
|
|
} from '../../components/TInput/TInput';
|
|
import TPanel from '../../components/TPanel/TPanel';
|
|
import TScroller from '../../components/TScroller/TScroller';
|
|
import TVerticalPagenator
|
|
from '../../components/TVerticalPagenator/TVerticalPagenator';
|
|
import TVirtualGridList
|
|
from '../../components/TVirtualGridList/TVirtualGridList';
|
|
// import VirtualKeyboardContainer from "../../components/TToast/VirtualKeyboardContainer";
|
|
import usePrevious from '../../hooks/usePrevious';
|
|
import {
|
|
LOG_CONTEXT_NAME,
|
|
LOG_MENU,
|
|
LOG_MESSAGE_ID,
|
|
panel_names,
|
|
} from '../../utils/Config';
|
|
import { SpotlightIds } from '../../utils/SpotlightIds';
|
|
import NoSearchResults from './NoSearchResults/NoSearchResults';
|
|
import RecommendedKeywords from './RecommendedKeywords/RecommendedKeywords';
|
|
import css from './SearchPanel.new.module.less';
|
|
import SearchResultsNew from './SearchResults.new';
|
|
|
|
const ContainerBasic = SpotlightContainerDecorator(
|
|
{ enterTo: "last-focused" },
|
|
"div"
|
|
);
|
|
|
|
// 검색 입력 영역 컨테이너
|
|
const InputContainer = SpotlightContainerDecorator(
|
|
{ enterTo: "last-focused" },
|
|
"div"
|
|
);
|
|
|
|
// 콘텐츠 섹션 컨테이너
|
|
const SectionContainer = SpotlightContainerDecorator(
|
|
{ enterTo: "last-focused" },
|
|
"div"
|
|
);
|
|
|
|
// Spottable 컴포넌트들
|
|
const SpottableMicButton = Spottable("div");
|
|
const SpottableKeyword = Spottable("div");
|
|
const SpottableProduct = Spottable("div");
|
|
const SpottableLi = Spottable("li");
|
|
|
|
const ITEMS_PER_PAGE = 9;
|
|
|
|
// Spotlight ID 상수
|
|
const SPOTLIGHT_IDS = {
|
|
SEARCH_INPUT_LAYER: "search-input-layer",
|
|
SEARCH_INPUT_BOX: "search-input-box",
|
|
MICROPHONE_BUTTON: "microphone-button",
|
|
RECENT_SEARCHES_SECTION: "recent-searches-section",
|
|
TOP_SEARCHES_SECTION: "top-searches-section",
|
|
POPULAR_BRANDS_SECTION: "popular-brands-section",
|
|
HOT_PICKS_SECTION: "hot-picks-section",
|
|
SEARCH_VERTICAL_PAGENATOR: "search_verticalPagenator",
|
|
};
|
|
|
|
export default function SearchPanel({
|
|
panelInfo,
|
|
isOnTop,
|
|
spotlightId,
|
|
scrollOptions = [],
|
|
}) {
|
|
const dispatch = useDispatch();
|
|
const loadingComplete = useSelector((state) => state.common?.loadingComplete);
|
|
const recommandedKeywords = useSelector(
|
|
(state) => state.myPage.recommandedKeywordData.data?.keywords
|
|
);
|
|
const { searchDatas: searchDatas } = useSelector((state) => state.search);
|
|
const searchPerformed = useSelector((state) => state.search.searchPerformed);
|
|
const panels = useSelector((state) => state.panels.panels);
|
|
|
|
const [firstSpot, setFirstSpot] = useState(false);
|
|
const [currentPage, setCurrentPage] = useState(1);
|
|
const [paginatedKeywords, setPaginatedKeywords] = useState([]);
|
|
const [pageChanged, setPageChanged] = useState(false);
|
|
const [searchQuery, setSearchQuery] = useState(
|
|
panelInfo.searchVal ? panelInfo.searchVal : null
|
|
);
|
|
const [position, setPosition] = useState(null);
|
|
const [showVirtualKeyboard, setShowVirtualKeyboard] = useState(false);
|
|
|
|
//인풋창 포커스 구분을 위함
|
|
const [inputFocus, setInputFocus] = useState(false);
|
|
const _onFocus = () => {
|
|
setInputFocus(true);
|
|
};
|
|
const _onBlur = () => {
|
|
setInputFocus(false);
|
|
};
|
|
useEffect(() => {
|
|
console.log("###inputFocus", inputFocus);
|
|
}, [inputFocus]);
|
|
|
|
let searchQueryRef = usePrevious(searchQuery);
|
|
let isOnTopRef = usePrevious(isOnTop);
|
|
|
|
const isRecommendedSearchRef = useRef(false);
|
|
|
|
const firstButtonSpotlightId = "first-keyword-button";
|
|
const focusJob = useRef(new Job((func) => func(), 100));
|
|
const cbChangePageRef = useRef(null);
|
|
const [focusedContainerId, setFocusedContainerId] = useState(
|
|
panelInfo?.focusedContainerId
|
|
);
|
|
const focusedContainerIdRef = usePrevious(focusedContainerId);
|
|
const bestSellerDatas = useSelector(
|
|
(state) => state.product.bestSellerData.bestSeller
|
|
);
|
|
|
|
// 가짜 데이터 - 실제로는 Redux store나 API에서 가져와야 함
|
|
const recentSearches = useMemo(
|
|
() => ["Puppy food", "Dog toy", "Fitness"],
|
|
[]
|
|
);
|
|
|
|
const recentResultSearches = useMemo(
|
|
() => [
|
|
"Puppy food",
|
|
"Dog toy",
|
|
"Mather's Day",
|
|
"Gift",
|
|
"Easter Day",
|
|
"Royal Canin puppy food",
|
|
"Shark",
|
|
],
|
|
[]
|
|
);
|
|
|
|
const topSearches = useMemo(
|
|
() => [
|
|
"Mather's Day",
|
|
"Gift",
|
|
"Easter Day",
|
|
"Royal Canin puppy food",
|
|
"Fitness",
|
|
"Parrot",
|
|
],
|
|
[]
|
|
);
|
|
const popularBrands = useMemo(
|
|
() => ["Shark", "Ninja", "Skechers", "LocknLock", "8Greens", "LGE"],
|
|
[]
|
|
);
|
|
const hotPicks = useMemo(
|
|
() => [
|
|
{
|
|
id: 1,
|
|
image: hotPicksImage,
|
|
brandLogo: hotPicksBrandImage,
|
|
brandName: "Product Name",
|
|
title: "New Shark Vacuum! Your pet Hair Solution!",
|
|
isForYou: false,
|
|
},
|
|
{
|
|
id: 2,
|
|
image: hotPicksImage,
|
|
brandLogo: hotPicksBrandImage,
|
|
brandName: "Product Name",
|
|
title: "New Shark Vacuum! Your pet Hair Solution!",
|
|
isForYou: false,
|
|
},
|
|
{
|
|
id: 3,
|
|
image: hotPicksImage,
|
|
brandLogo: hotPicksBrandImage,
|
|
brandName: "Product Name",
|
|
title: "New Shark Vacuum! Your pet Hair Solution!",
|
|
isForYou: false,
|
|
},
|
|
{
|
|
id: 4,
|
|
image: hotPicksImage,
|
|
brandLogo: hotPicksBrandImage,
|
|
brandName: "Product Name",
|
|
title: "New Shark Vacuum! Your pet Hair Solution!",
|
|
isForYou: true,
|
|
},
|
|
],
|
|
[]
|
|
);
|
|
|
|
useEffect(() => {
|
|
if (loadingComplete && !recommandedKeywords) {
|
|
dispatch(getMyRecommandedKeyword());
|
|
}
|
|
}, [loadingComplete]);
|
|
|
|
useEffect(() => {
|
|
if (isOnTop) {
|
|
let menu;
|
|
if (!searchPerformed) menu = LOG_MENU.SEARCH_SEARCH;
|
|
else {
|
|
if (searchQueryRef.current)
|
|
menu =
|
|
Object.keys(searchDatas).length > 0
|
|
? LOG_MENU.SEARCH_RESULT
|
|
: LOG_MENU.SEARCH_BEST_SELLER;
|
|
}
|
|
dispatch(sendLogGNB(menu));
|
|
}
|
|
}, [isOnTop, searchDatas, searchPerformed]);
|
|
|
|
useEffect(() => {
|
|
if (!searchQuery) {
|
|
dispatch(resetSearch());
|
|
}
|
|
}, [dispatch]);
|
|
|
|
useEffect(() => {
|
|
if (recommandedKeywords) {
|
|
const startIndex = (currentPage - 1) * ITEMS_PER_PAGE;
|
|
const endIndex = startIndex + ITEMS_PER_PAGE;
|
|
|
|
setPaginatedKeywords(recommandedKeywords.slice(startIndex, endIndex));
|
|
}
|
|
}, [recommandedKeywords, currentPage]);
|
|
|
|
useEffect(() => {
|
|
if (pageChanged && paginatedKeywords.length > 0) {
|
|
Spotlight.focus(firstButtonSpotlightId);
|
|
|
|
setPageChanged(false);
|
|
}
|
|
}, [pageChanged, paginatedKeywords]);
|
|
|
|
const handleSearchChange = useCallback((e) => {
|
|
const query = e.value;
|
|
|
|
if (query.length <= 255) {
|
|
setSearchQuery(query);
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
const result = Object.values(searchDatas).reduce((acc, curr) => {
|
|
return acc + curr.length;
|
|
}, 0);
|
|
|
|
if (searchQuery) {
|
|
dispatch(
|
|
sendLogTotalRecommend({
|
|
query: searchQuery,
|
|
searchType: searchPerformed ? "query" : "keyword",
|
|
result: result,
|
|
contextName: LOG_CONTEXT_NAME.SEARCH,
|
|
messageId: LOG_MESSAGE_ID.SEARCH_ITEM,
|
|
})
|
|
);
|
|
|
|
// 검색 완료 후 결과에 따른 Toast 표시
|
|
if (searchPerformed && searchQuery.trim()) {
|
|
if (result > 0) {
|
|
dispatch(showSearchSuccessToast(searchQuery, result));
|
|
} else {
|
|
dispatch(showSearchErrorToast(searchQuery));
|
|
}
|
|
}
|
|
}
|
|
}, [searchDatas, searchPerformed, searchQuery, dispatch]);
|
|
|
|
const handleSearchSubmit = useCallback(
|
|
(query) => {
|
|
if (!searchPerformed && !query) return;
|
|
if (query.trim()) {
|
|
dispatch(
|
|
getSearch({
|
|
service: "com.lgshop.app",
|
|
query: query,
|
|
domain: "theme,show,item",
|
|
})
|
|
);
|
|
|
|
// 검색 시작 알림 (선택사항)
|
|
dispatch(showSuccessToast(`"${query}" 검색 중...`, { duration: 2000 }));
|
|
} else {
|
|
dispatch(resetSearch());
|
|
}
|
|
setSearchQuery(query);
|
|
// 검색 시 가상 키보드 숨김
|
|
setShowVirtualKeyboard(false);
|
|
},
|
|
[dispatch, searchPerformed, searchDatas, searchQuery]
|
|
);
|
|
|
|
const handleNext = useCallback(() => {
|
|
if (!isOnTopRef.current) {
|
|
return;
|
|
}
|
|
setCurrentPage((prev) => prev + 1);
|
|
setPageChanged(true);
|
|
}, [currentPage]);
|
|
|
|
const handlePrev = useCallback(() => {
|
|
if (!isOnTopRef.current) {
|
|
return;
|
|
}
|
|
setCurrentPage((prev) => (prev > 1 ? prev - 1 : prev));
|
|
setPageChanged(true);
|
|
}, [currentPage]);
|
|
|
|
const hasPrevPage = currentPage > 1;
|
|
const hasNextPage =
|
|
currentPage * ITEMS_PER_PAGE < recommandedKeywords?.length;
|
|
|
|
useEffect(() => {
|
|
if (panelInfo && isOnTop) {
|
|
if (panelInfo.currentSpot && firstSpot) {
|
|
Spotlight.focus(panel_names.SEARCH_PANEL);
|
|
}
|
|
}
|
|
}, [panelInfo, isOnTop]);
|
|
|
|
useEffect(() => {
|
|
return () => {
|
|
dispatch(
|
|
updatePanel({
|
|
name: panel_names.SEARCH_PANEL,
|
|
panelInfo: {
|
|
searchVal: searchQueryRef.current,
|
|
focusedContainerId: focusedContainerIdRef.current,
|
|
},
|
|
})
|
|
);
|
|
};
|
|
}, []);
|
|
|
|
const handleKeydown = useCallback(
|
|
(e) => {
|
|
if (!isOnTopRef.current) {
|
|
return;
|
|
}
|
|
|
|
// Enter 키 처리
|
|
if (e.key === "Enter") {
|
|
e.preventDefault();
|
|
if (showVirtualKeyboard) {
|
|
// 가상 키보드가 열려있으면 검색 실행하고 키보드 닫기
|
|
handleSearchSubmit(searchQuery);
|
|
} else {
|
|
// 가상 키보드가 닫혀있으면 키보드 열기
|
|
setShowVirtualKeyboard(true);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// 방향키 처리 - Spotlight 네비게이션 허용
|
|
const arrowKeys = [
|
|
"ArrowLeft",
|
|
"ArrowRight",
|
|
"ArrowUp",
|
|
"ArrowDown",
|
|
"Left",
|
|
"Right",
|
|
"Up",
|
|
"Down",
|
|
];
|
|
if (arrowKeys.includes(e.key)) {
|
|
// 입력 필드가 비어있고 왼쪽 화살표인 경우에만 방지
|
|
if (
|
|
position === 0 &&
|
|
(e.key === "Left" || e.key === "ArrowLeft") &&
|
|
!searchQuery
|
|
) {
|
|
e.preventDefault();
|
|
return;
|
|
}
|
|
|
|
// 오른쪽 화살표 키 처리 - 포커스 이동 허용
|
|
if (e.key === "ArrowRight" || e.key === "Right") {
|
|
// 커서가 텍스트 끝에 있을 때만 포커스 이동 허용
|
|
const input = document.querySelector(
|
|
`[data-spotlight-id="input-field-box"] > input`
|
|
);
|
|
if (input && position === input.value.length) {
|
|
// 커서가 텍스트 끝에 있으면 포커스 이동 허용
|
|
return;
|
|
}
|
|
}
|
|
|
|
// 나머지 방향키는 Spotlight가 처리하도록 허용
|
|
return;
|
|
}
|
|
},
|
|
[searchQuery, position, handleSearchSubmit, showVirtualKeyboard]
|
|
);
|
|
|
|
const cursorPosition = useCallback(() => {
|
|
const input = document.querySelector(
|
|
`[data-spotlight-id="input-field-box"] > input`
|
|
);
|
|
if (input) {
|
|
setPosition(input.selectionStart);
|
|
}
|
|
}, []);
|
|
|
|
const onCancel = useCallback(() => {
|
|
if (!isOnTopRef.current) {
|
|
return;
|
|
}
|
|
if (searchQuery === null || searchQuery === "") {
|
|
dispatch(popPanel(panel_names.SEARCH_PANEL));
|
|
} else {
|
|
setSearchQuery("");
|
|
setCurrentPage(1);
|
|
dispatch(resetSearch());
|
|
Spotlight.focus(SPOTLIGHT_IDS.SEARCH_INPUT_BOX);
|
|
}
|
|
}, [searchQuery, dispatch]);
|
|
|
|
const onFocusedContainerId = useCallback(
|
|
(containerId) => {
|
|
setFocusedContainerId(containerId);
|
|
if (!firstSpot) {
|
|
setTimeout(() => {
|
|
Spotlight.resume();
|
|
setFirstSpot(true);
|
|
if (panelInfo.currentSpot) {
|
|
if (panels[panels.length - 1]?.name === "searchpanel") {
|
|
Spotlight.focus(panelInfo.currentSpot);
|
|
}
|
|
}
|
|
}, 0);
|
|
}
|
|
},
|
|
[panelInfo, firstSpot]
|
|
);
|
|
|
|
const panelInfoFall = useMemo(() => {
|
|
const newPanelInfo = { ...panelInfo };
|
|
if (firstSpot) {
|
|
newPanelInfo.currentSpot = null;
|
|
}
|
|
return newPanelInfo;
|
|
}, [panelInfo, firstSpot]);
|
|
|
|
// 키워드 클릭 핸들러
|
|
const handleKeywordClick = useCallback(
|
|
(keyword) => {
|
|
setSearchQuery(keyword);
|
|
handleSearchSubmit(keyword);
|
|
// 키워드 선택 알림
|
|
dispatch(
|
|
showSuccessToast(`"${keyword}" 키워드로 검색합니다.`, {
|
|
duration: 2000,
|
|
})
|
|
);
|
|
},
|
|
[handleSearchSubmit, dispatch]
|
|
);
|
|
|
|
// 상품 클릭 핸들러
|
|
const handleProductClick = useCallback((product) => {
|
|
// 상품 상세 페이지로 이동하는 로직 구현
|
|
console.log("Product clicked:", product);
|
|
}, []);
|
|
|
|
// 테스트용 Toast 핸들러들
|
|
const handleTestToasts = useCallback(() => {
|
|
// 간단한 Toast 테스트
|
|
dispatch(showSuccessToast("테스트 메시지입니다", { duration: 3000 }));
|
|
}, [dispatch]);
|
|
|
|
// ProductCard 컴포넌트
|
|
const renderItem = useCallback(
|
|
(
|
|
// {
|
|
// product,
|
|
// index,
|
|
// onClick,
|
|
// showBrandLogo = true,
|
|
// showBrandName = true,
|
|
// showProductTitle = true,
|
|
// ...rest
|
|
// }
|
|
{ index, ...rest }
|
|
) => {
|
|
const {
|
|
showBrandLogo = true,
|
|
showBrandName = true,
|
|
showProductTitle = true,
|
|
image,
|
|
title,
|
|
brandLogo,
|
|
brandName,
|
|
} = hotPicks[index];
|
|
return (
|
|
<SpottableProduct
|
|
key={`product-${index}`}
|
|
className={css.productCard}
|
|
spotlightId={`product-${index}`}
|
|
{...rest}
|
|
>
|
|
<div className={css.productImageWrapper}>
|
|
<img src={image} alt={title} className={css.productImage} />
|
|
</div>
|
|
<div className={css.productInfo}>
|
|
{showBrandLogo && (
|
|
<div className={css.productBrandWrapper}>
|
|
<img
|
|
src={brandLogo}
|
|
alt={brandName}
|
|
className={css.brandLogo}
|
|
/>
|
|
</div>
|
|
)}
|
|
<div className={css.productDetails}>
|
|
{showBrandName && (
|
|
<div className={css.brandName}>{brandName}</div>
|
|
)}
|
|
{showProductTitle && (
|
|
<div className={css.productTitle}>{title}</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</SpottableProduct>
|
|
);
|
|
},
|
|
[]
|
|
);
|
|
|
|
return (
|
|
<TPanel
|
|
className={css.container}
|
|
handleCancel={onCancel}
|
|
spotlightId={spotlightId}
|
|
>
|
|
<TBody
|
|
className={css.tBody}
|
|
scrollable={true}
|
|
spotlightDisabled={!isOnTop}
|
|
>
|
|
<ContainerBasic>
|
|
{isOnTop && (
|
|
<TVerticalPagenator
|
|
className={css.tVerticalPagenator}
|
|
spotlightId={SPOTLIGHT_IDS.SEARCH_VERTICAL_PAGENATOR}
|
|
defaultContainerId={panelInfo?.focusedContainerId}
|
|
disabled={!isOnTop}
|
|
onFocusedContainerId={onFocusedContainerId}
|
|
cbChangePageRef={cbChangePageRef}
|
|
topMargin={36}
|
|
scrollable={true}
|
|
>
|
|
{/* 검색 내용있을때 검색 부분 */}
|
|
{/* 검색 입력 영역 */}
|
|
<InputContainer
|
|
className={classNames(
|
|
css.inputContainer,
|
|
inputFocus === true && css.inputFocus,
|
|
css.searchValue /* 이건 결과값 있을때만. 조건 추가필요 */
|
|
)}
|
|
data-wheel-point={true}
|
|
spotlightId={SPOTLIGHT_IDS.SEARCH_INPUT_LAYER}
|
|
>
|
|
<div className={css.searchInputWrapper}>
|
|
<TInput
|
|
className={css.inputBox}
|
|
kind={KINDS.withIcon}
|
|
icon={ICONS.search}
|
|
value={searchQuery}
|
|
onChange={handleSearchChange}
|
|
onIconClick={() => {
|
|
if (showVirtualKeyboard) {
|
|
handleSearchSubmit(searchQuery);
|
|
} else {
|
|
setShowVirtualKeyboard(true);
|
|
}
|
|
}}
|
|
onKeyDown={handleKeydown}
|
|
onKeyUp={cursorPosition}
|
|
spotlightId={SPOTLIGHT_IDS.SEARCH_INPUT_BOX}
|
|
forcedSpotlight="recent-keyword-0"
|
|
tabIndex={0}
|
|
spotlightDisabled={false}
|
|
spotlightBoxDisabled={true}
|
|
onFocus={_onFocus}
|
|
onBlur={_onBlur}
|
|
/>
|
|
<SpottableMicButton
|
|
className={css.microphoneButton}
|
|
onClick={onCancel}
|
|
spotlightId={SPOTLIGHT_IDS.MICROPHONE_BUTTON}
|
|
>
|
|
<div className={css.microphoneCircle}>
|
|
<img
|
|
src={micIcon}
|
|
alt="Microphone"
|
|
className={css.microphoneIcon}
|
|
/>
|
|
</div>
|
|
</SpottableMicButton>
|
|
|
|
{/* 테스트용 Toast 버튼 (개발용) */}
|
|
{/* <SpottableMicButton
|
|
className={css.testToastButton}
|
|
onClick={handleTestToasts}
|
|
spotlightId="test-toast-button"
|
|
>
|
|
<div className={css.testButtonCircle}>🧪</div>
|
|
</SpottableMicButton> */}
|
|
</div>
|
|
</InputContainer>
|
|
|
|
{/* 검색내용이 존재하고, 인풋창에 포커스가 가서 노출 시작 */}
|
|
{/* 피그마 기준 첫번째 줄 마지막 이미지 */}
|
|
{/* <div className={css.overLay}></div>
|
|
<div className={css.overLayRecent}>
|
|
{recentResultSearches.map((keyword, index) => (
|
|
<SpottableKeyword
|
|
key={`recentResult-${index}`}
|
|
className={css.keywordButton}
|
|
onClick={() => handleKeywordClick(keyword)}
|
|
spotlightId={`recent-Resultkeyword-${index}`}
|
|
>
|
|
{keyword}
|
|
</SpottableKeyword>
|
|
))}
|
|
</div> */}
|
|
{/* 검색내용이 존재하고, 인풋창에 포커스가 가서 노출 끝! */}
|
|
|
|
{/* 결과갑 부분 작업중 시작! */}
|
|
|
|
{/* 결과갑 부분 작업중 끝! */}
|
|
{/* 검색 결과 표시 영역 */}
|
|
{searchPerformed && searchQuery !== null ? (
|
|
<SearchResultsNew />
|
|
) : (
|
|
<ContainerBasic className={css.contentContainer}>
|
|
{/* 노출 조건 변경 필요. 포커스 블러만으로는 안됌.(가상 키보드 노출시가 맞을듯) */}
|
|
{inputFocus === false ? (
|
|
<>
|
|
{/* 최근 검색어 섹션 */}
|
|
<SectionContainer
|
|
className={css.section}
|
|
data-wheel-point={true}
|
|
spotlightId={SPOTLIGHT_IDS.RECENT_SEARCHES_SECTION}
|
|
>
|
|
<div className={css.sectionHeader}>
|
|
<div className={css.sectionIndicator}></div>
|
|
<div className={css.sectionTitle}>
|
|
Your Recent Searches
|
|
</div>
|
|
</div>
|
|
<div className={css.keywordList}>
|
|
{recentSearches.map((keyword, index) => (
|
|
<SpottableKeyword
|
|
key={`recent-${index}`}
|
|
className={css.keywordButton}
|
|
onClick={() => handleKeywordClick(keyword)}
|
|
spotlightId={`recent-keyword-${index}`}
|
|
>
|
|
{keyword}
|
|
</SpottableKeyword>
|
|
))}
|
|
</div>
|
|
</SectionContainer>
|
|
|
|
{/* 인기 검색어 섹션 */}
|
|
<SectionContainer
|
|
className={css.section}
|
|
data-wheel-point={true}
|
|
spotlightId={SPOTLIGHT_IDS.TOP_SEARCHES_SECTION}
|
|
>
|
|
<div className={css.sectionHeader}>
|
|
<div className={css.sectionIndicator}></div>
|
|
<div className={css.sectionTitle}>Top Searches</div>
|
|
</div>
|
|
<div className={css.keywordList}>
|
|
{topSearches.map((keyword, index) => (
|
|
<SpottableKeyword
|
|
key={`top-${index}`}
|
|
className={css.keywordButton}
|
|
onClick={() => handleKeywordClick(keyword)}
|
|
spotlightId={`top-keyword-${index}`}
|
|
>
|
|
{keyword}
|
|
</SpottableKeyword>
|
|
))}
|
|
</div>
|
|
</SectionContainer>
|
|
|
|
{/* 인기 브랜드 섹션 */}
|
|
<SectionContainer
|
|
className={css.section}
|
|
data-wheel-point={true}
|
|
spotlightId={SPOTLIGHT_IDS.POPULAR_BRANDS_SECTION}
|
|
>
|
|
<div className={css.sectionHeader}>
|
|
<div className={css.sectionIndicator}></div>
|
|
<div className={css.sectionTitle}>Popular Brands</div>
|
|
</div>
|
|
<div className={css.keywordList}>
|
|
{popularBrands.map((brand, index) => (
|
|
<SpottableKeyword
|
|
key={`brand-${index}`}
|
|
className={css.keywordButton}
|
|
onClick={() => handleKeywordClick(brand)}
|
|
spotlightId={`brand-${index}`}
|
|
>
|
|
{brand}
|
|
</SpottableKeyword>
|
|
))}
|
|
</div>
|
|
</SectionContainer>
|
|
|
|
{/* Hot Picks for You 섹션 */}
|
|
<SectionContainer
|
|
className={css.hotpicksSection}
|
|
data-wheel-point={true}
|
|
spotlightId={SPOTLIGHT_IDS.HOT_PICKS_SECTION}
|
|
>
|
|
<div className={css.sectionHeader}>
|
|
<div className={css.sectionIndicator}></div>
|
|
<div className={css.sectionTitle}>
|
|
Hot Picks for You
|
|
</div>
|
|
</div>
|
|
<div className={css.productList}>
|
|
{hotPicks && hotPicks.length > 0 && (
|
|
<TVirtualGridList
|
|
dataSize={hotPicks.length}
|
|
direction="horizontal"
|
|
renderItem={renderItem}
|
|
// itemWidth={546}
|
|
itemWidth={416}
|
|
itemHeight={436}
|
|
spacing={20}
|
|
/>
|
|
)}
|
|
</div>
|
|
</SectionContainer>
|
|
</>
|
|
) : (
|
|
<div className={css.inputFocusBox}>
|
|
<div className={css.keywordList}>
|
|
{recentSearches.map((keyword, index) => (
|
|
<SpottableKeyword
|
|
key={`recent-${index}`}
|
|
className={css.keywordButton}
|
|
onClick={() => handleKeywordClick(keyword)}
|
|
spotlightId={`recent-keyword-${index}`}
|
|
>
|
|
{keyword}
|
|
</SpottableKeyword>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</ContainerBasic>
|
|
)}
|
|
</TVerticalPagenator>
|
|
)}
|
|
</ContainerBasic>
|
|
</TBody>
|
|
|
|
{/* Virtual Keyboard */}
|
|
{/* <VirtualKeyboardContainer
|
|
isVisible={showVirtualKeyboard}
|
|
onClose={() => setShowVirtualKeyboard(false)}
|
|
/> */}
|
|
</TPanel>
|
|
);
|
|
}
|