diff --git a/com.twin.app.shoptime/src/api/TAxios.js b/com.twin.app.shoptime/src/api/TAxios.js
index acaa9f7a..f179f1e8 100644
--- a/com.twin.app.shoptime/src/api/TAxios.js
+++ b/com.twin.app.shoptime/src/api/TAxios.js
@@ -99,6 +99,23 @@ export const TAxios = async (
AUTHORIZATION.headers["sdk_ver"] = "1.0.0";
AUTHORIZATION.headers["publish_flag"] = "Y";
+ // Device Header 임시
+ AUTHORIZATION.headers["X-Authentication"] = "MkOLvUocrJ69RH/iV1ZABJhjR2g=";
+ AUTHORIZATION.headers["X-Device-ID"] =
+ "OemUY5qbPITZv96QKlxrtcqT6ypeX6us2qANLng3/0QCUhv2mecK1UDTMYb/hjpjey9dC/kFycc/5R8u+oK56JIWyYC4V278z64YDPKbDXIsd+eECvyf+Rdm8BneIUPM";
+ AUTHORIZATION.headers["X-Device-Product"] = "webOSTV 5.0";
+ AUTHORIZATION.headers["X-Device-Platform"] = "W20P";
+ AUTHORIZATION.headers["X-Device-Model"] = "HE_DTV_W20P_AFADATAA";
+ AUTHORIZATION.headers["X-Device-Eco-Info"] = "1";
+ AUTHORIZATION.headers["X-Device-Country"] = "US";
+ AUTHORIZATION.headers["X-Device-Language"] = "en-US";
+ AUTHORIZATION.headers["X-Device-Netcast-Platform-Version"] = "5.0.0";
+ AUTHORIZATION.headers["X-Device-Publish-Flag"] = "N";
+ AUTHORIZATION.headers["X-Device-Fck"] = "253";
+ AUTHORIZATION.headers["X-Device-Eula"] =
+ "additionalDataAllowed,takeOnAllowed,networkAllowed,generalTermsAllowed,chpAllowed,customAdAllowed,acrOnAllowed,voice2Allowed,voiceAllowed,acrAdAllowed";
+ AUTHORIZATION.headers["X-Device-Personalization"] = "Y";
+
if (
baseUrl !== URLS.GET_AUTHENTICATION_CODE &&
!accessToken &&
diff --git a/com.twin.app.shoptime/src/api/apiConfig.js b/com.twin.app.shoptime/src/api/apiConfig.js
index 213f6a80..c8a83d32 100644
--- a/com.twin.app.shoptime/src/api/apiConfig.js
+++ b/com.twin.app.shoptime/src/api/apiConfig.js
@@ -34,6 +34,9 @@ export const URLS = {
//my-page controller
GET_MY_RECOMMANDED_KEYWORD: "/lgsp/v1/mypage/reckeyword.lge",
+ //search controller
+ GET_SEARCH: "/lgsp/v1/search/list.lge",
+
//main controller
GET_SUB_CATEGORY: "/lgsp/v1/main/subcategory.lge",
};
diff --git a/com.twin.app.shoptime/src/components/TInput/TInput.jsx b/com.twin.app.shoptime/src/components/TInput/TInput.jsx
index 02a9db84..de66c7d1 100644
--- a/com.twin.app.shoptime/src/components/TInput/TInput.jsx
+++ b/com.twin.app.shoptime/src/components/TInput/TInput.jsx
@@ -4,11 +4,10 @@ import { InputField } from "@enact/sandstone/Input";
import Spottable from "@enact/spotlight/Spottable";
import classNames from "classnames";
import { SpotlightContainerDecorator } from "@enact/spotlight/SpotlightContainerDecorator";
+import TIconButton from "../TIconButton/TIconButton";
const Container = SpotlightContainerDecorator("div");
-const SpottableInputIcon = Spottable("div");
-
const KINDS = { withIcon: "withIcon" };
const ICONS = { search: "search" };
const BORDER = { none: "none" };
@@ -21,10 +20,10 @@ export default function TInput({
color,
className,
spotlightDisabled,
+ disabled,
+ onIconClick,
...rest
}) {
- const handleIconClick = useCallback(() => {}, []);
-
return (
{kind === "withIcon" && (
-
)}
diff --git a/com.twin.app.shoptime/src/features/search/searchSlice.js b/com.twin.app.shoptime/src/features/search/searchSlice.js
new file mode 100644
index 00000000..f5663ef8
--- /dev/null
+++ b/com.twin.app.shoptime/src/features/search/searchSlice.js
@@ -0,0 +1,51 @@
+import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
+import { URLS } from "../../api/apiConfig";
+import { TAxios } from "../../api/TAxios";
+
+// Search 통합검색 (IBS) 데이터 조회 IF-LGSP-090
+export const getSearch = createAsyncThunk(
+ "search/getSearch",
+
+ async (params, thunkAPI) => {
+ const { service, query, startIndex, maxResults, domain } = params;
+
+ const onSuccess = (response) => {
+ console.log("getSearch onSuccess: ", response.data);
+
+ thunkAPI.dispatch(updateSearchData(response.data));
+ };
+
+ const onFail = (error) => {
+ console.error("getSearch onFail: ", error);
+ };
+
+ TAxios(
+ thunkAPI.dispatch,
+ thunkAPI.getState,
+ "post",
+ URLS.GET_SEARCH,
+ {},
+ { service, query, startIndex, maxResults, domain },
+ onSuccess,
+ onFail
+ );
+ }
+);
+
+const initialState = {
+ searchDatas: {},
+};
+
+export const searchSlice = createSlice({
+ name: "search",
+ initialState,
+ reducers: {
+ updateSearchData: (state, action) => {
+ state.searchDatas = action.payload;
+ },
+ },
+});
+
+export const { updateSearchData } = searchSlice.actions;
+
+export default searchSlice.reducer;
diff --git a/com.twin.app.shoptime/src/store/store.js b/com.twin.app.shoptime/src/store/store.js
index 8d2e7fc8..043d8fed 100644
--- a/com.twin.app.shoptime/src/store/store.js
+++ b/com.twin.app.shoptime/src/store/store.js
@@ -7,8 +7,9 @@ import deviceReducer from "../features/device/deviceSlice";
import homeReducer from "../features/home/homeSlice";
import myPageReducer from "../features/mypage/myPageSlice";
import onSaleReducer from "../features/onSale/onSaleSlice";
-import productReducer from "../features/product/productSlice";
import panelsReducer from "../features/panels/panelsSlice";
+import searchReducer from "../features/search/searchSlice";
+import productReducer from "../features/product/productSlice";
import mainReducer from "../features/main/mainSlice";
export const store = configureStore({
@@ -21,6 +22,7 @@ export const store = configureStore({
onSale: onSaleReducer,
brand: brandReducer,
myPage: myPageReducer,
+ search: searchReducer,
product: productReducer,
main: mainReducer,
},
diff --git a/com.twin.app.shoptime/src/views/LoadingPanel/LoadingPanel.jsx b/com.twin.app.shoptime/src/views/LoadingPanel/LoadingPanel.jsx
index b48da7da..82212a1f 100644
--- a/com.twin.app.shoptime/src/views/LoadingPanel/LoadingPanel.jsx
+++ b/com.twin.app.shoptime/src/views/LoadingPanel/LoadingPanel.jsx
@@ -149,6 +149,14 @@ export default function LoadingPanel({ showLoadingPanel, ...rest }) {
src={loadingImage}
>
);
+
+ case "wait":
+ return (
+
+ );
+
default:
return null;
}
diff --git a/com.twin.app.shoptime/src/views/LoadingPanel/LoadingPanel.module.less b/com.twin.app.shoptime/src/views/LoadingPanel/LoadingPanel.module.less
index 67b32683..56445ef4 100644
--- a/com.twin.app.shoptime/src/views/LoadingPanel/LoadingPanel.module.less
+++ b/com.twin.app.shoptime/src/views/LoadingPanel/LoadingPanel.module.less
@@ -27,3 +27,14 @@
width: auto;
height: auto;
}
+
+.wait {
+ background-color: rgba(0, 0, 0, 0.7);
+ width: 100%;
+ height: 100%;
+ .flex();
+
+ > p {
+ color: #fff;
+ }
+}
diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.jsx b/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.jsx
index 35f91383..61028e5d 100644
--- a/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.jsx
+++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.jsx
@@ -12,6 +12,10 @@ import TIconButton, {
import classNames from "classnames";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
+import Spotlight from "@enact/spotlight";
+
+import { changeAppStatus } from "../../features/common/commonSlice";
+import { getSearch } from "../../features/search/searchSlice";
const Container = SpotlightContainerDecorator(
{ enterTo: "last-focused" },
@@ -21,12 +25,22 @@ const Container = SpotlightContainerDecorator(
const ITEMS_PER_PAGE = 9;
export default function SearchPanel() {
+ const dispatch = useDispatch();
+
+ const { showLoadingPanel } = useSelector((state) => state.common.appStatus);
const recommandedKeywords = useSelector(
(state) => state.myPage.recommandedKeywordData.data?.keywords
);
+ const searchDatas = useSelector(
+ (state) => state.search.searchDatas.data?.result.results
+ );
const [currentPage, setCurrentPage] = useState(1);
const [paginatedKeywords, setPaginatedKeywords] = useState([]);
+ const [pageChanged, setPageChanged] = useState(false);
+
+ const [searchQuery, setSearchQuery] = useState("");
+ const [searchPerformed, setSearchPerformed] = useState(false);
useEffect(() => {
if (recommandedKeywords) {
@@ -37,18 +51,101 @@ export default function SearchPanel() {
}
}, [recommandedKeywords, currentPage]);
+ useEffect(() => {
+ if (pageChanged && paginatedKeywords.length > 0) {
+ const firstButtonSpotlightId = "first-keyword-button";
+
+ Spotlight.focus(firstButtonSpotlightId);
+
+ setPageChanged(false);
+ }
+ }, [pageChanged, paginatedKeywords]);
+
+ const handleSearchChange = useCallback((e) => {
+ const query = e.value;
+
+ if (query.length <= 255) {
+ setSearchQuery(query);
+ }
+ }, []);
+
+ const handleSearchSubmit = useCallback(async () => {
+ setSearchPerformed(true);
+
+ if (searchQuery.trim() === "") {
+ setSearchPerformed(false);
+ return;
+ }
+
+ try {
+ await dispatch(
+ getSearch({
+ service: "com.lgshop.app",
+ query: searchQuery,
+ startIndex: 1,
+ maxResults: 10,
+ domain: "theme,show,item",
+ })
+ ).unwrap();
+ } catch (error) {
+ console.error("Search request failed: ", error);
+ }
+ }, [searchQuery, dispatch]);
+
const handleNext = useCallback(() => {
setCurrentPage((prev) => prev + 1);
+ setPageChanged(true);
}, [currentPage]);
const handlePrev = useCallback(() => {
setCurrentPage((prev) => (prev > 1 ? prev - 1 : prev));
+ setPageChanged(true);
}, [currentPage]);
const hasPrevPage = currentPage > 1;
const hasNextPage =
currentPage * ITEMS_PER_PAGE < recommandedKeywords?.length;
+ const renderContents = () => {
+ if (searchPerformed) {
+ if (searchDatas && searchDatas.length > 0) {
+ return
data!!
;
+ } else {
+ return SORRY
;
+ }
+ } else {
+ return (
+ <>
+ {hasPrevPage && (
+
+ )}
+
+ {paginatedKeywords.map((keyword, index) => (
+
+ {keyword.keywd}
+
+ ))}
+
+ {hasNextPage && (
+
+ )}
+ >
+ );
+ }
+ };
+
return (
- {hasPrevPage && (
-
- )}
-
- {paginatedKeywords.map((keyword, index) => (
-
- {keyword.keywd}
-
- ))}
-
- {hasNextPage && (
-
- )}
+ {renderContents()}
);
}