TAxios에 Device Header 임시값 추가, TInput, SearchPanel 작업 중
This commit is contained in:
@@ -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 &&
|
||||
|
||||
@@ -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",
|
||||
};
|
||||
|
||||
@@ -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 (
|
||||
<Container
|
||||
className={classNames(css.container, className ? className : null)}
|
||||
@@ -33,12 +32,11 @@ export default function TInput({
|
||||
{...rest}
|
||||
spotlightDisabled={spotlightDisabled}
|
||||
className={classNames(css.input)}
|
||||
spotlightId="input"
|
||||
/>
|
||||
{kind === "withIcon" && (
|
||||
<SpottableInputIcon
|
||||
<TIconButton
|
||||
className={classNames(icon && css[icon])}
|
||||
onClick={handleIconClick}
|
||||
onClick={onIconClick}
|
||||
/>
|
||||
)}
|
||||
</Container>
|
||||
|
||||
51
com.twin.app.shoptime/src/features/search/searchSlice.js
Normal file
51
com.twin.app.shoptime/src/features/search/searchSlice.js
Normal file
@@ -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;
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -149,6 +149,14 @@ export default function LoadingPanel({ showLoadingPanel, ...rest }) {
|
||||
src={loadingImage}
|
||||
></CustomImage>
|
||||
);
|
||||
|
||||
case "wait":
|
||||
return (
|
||||
<section className={css.wait}>
|
||||
<p>LOADING...</p>
|
||||
</section>
|
||||
);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <div>data!!</div>;
|
||||
} else {
|
||||
return <div>SORRY</div>;
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
{hasPrevPage && (
|
||||
<TIconButton
|
||||
iconType={ICON_TYPES.leftArrow}
|
||||
className={classNames(css.arrow, css.arrowLeft)}
|
||||
onClick={handlePrev}
|
||||
/>
|
||||
)}
|
||||
<Container className={css.keywordsGrid}>
|
||||
{paginatedKeywords.map((keyword, index) => (
|
||||
<TButton
|
||||
key={index}
|
||||
spotlightId={index === 0 ? "first-keyword-button" : undefined}
|
||||
className={classNames(css.keywordBox)}
|
||||
>
|
||||
{keyword.keywd}
|
||||
</TButton>
|
||||
))}
|
||||
</Container>
|
||||
{hasNextPage && (
|
||||
<TIconButton
|
||||
iconType={ICON_TYPES.rightArrow}
|
||||
className={classNames(css.arrow, css.arrowRight)}
|
||||
onClick={handleNext}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<TPanel className={css.panel}>
|
||||
<TInput
|
||||
@@ -56,28 +153,11 @@ export default function SearchPanel() {
|
||||
autoFocus
|
||||
kind={KINDS.withIcon}
|
||||
icon={ICONS.search}
|
||||
value={searchQuery}
|
||||
onChange={handleSearchChange}
|
||||
onIconClick={handleSearchSubmit}
|
||||
/>
|
||||
{hasPrevPage && (
|
||||
<TIconButton
|
||||
iconType={ICON_TYPES.leftArrow}
|
||||
className={classNames(css.arrow, css.arrowLeft)}
|
||||
onClick={handlePrev}
|
||||
/>
|
||||
)}
|
||||
<Container className={css.keywordsGrid}>
|
||||
{paginatedKeywords.map((keyword, index) => (
|
||||
<TButton key={index} className={css.keywordBox}>
|
||||
{keyword.keywd}
|
||||
</TButton>
|
||||
))}
|
||||
</Container>
|
||||
{hasNextPage && (
|
||||
<TIconButton
|
||||
iconType={ICON_TYPES.rightArrow}
|
||||
className={classNames(css.arrow, css.arrowRight)}
|
||||
onClick={handleNext}
|
||||
/>
|
||||
)}
|
||||
{renderContents()}
|
||||
</TPanel>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user