detail 레이아웃 작업 및 indicator추가 TButton BackKey props 추가
This commit is contained in:
@@ -34,6 +34,7 @@ export const types = {
|
||||
GET_SUB_CATEGORY: "GET_SUB_CATEGORY",
|
||||
APPEND_SUB_CATEGORY: "APPEND_SUB_CATEGORY",
|
||||
GET_TOP_20_SHOW: "GET_TOP_20_SHOW",
|
||||
GET_PRODUCT_DETAIL: "GET_PRODUCT_DETAIL",
|
||||
|
||||
// myPage actions
|
||||
GET_MY_RECOMMANDED_KEYWORD: "GET_MY_RECOMMANDED_KEYWORD",
|
||||
@@ -44,6 +45,8 @@ export const types = {
|
||||
|
||||
// product actions
|
||||
GET_BEST_SELLER: "GET_BEST_SELLER",
|
||||
GET_PRODUCT_GROUP: "GET_PRODUCT_GROUP",
|
||||
GET_PRODUCT_OPTION: "GET_PRODUCT_OPTION",
|
||||
|
||||
// search actions
|
||||
GET_SEARCH: "GET_SEARCH",
|
||||
|
||||
@@ -5,6 +5,33 @@ import { types } from "./actionTypes";
|
||||
|
||||
// 서브카테고리 조회 IF-LGSP-051
|
||||
let getSubCategoryKey = null;
|
||||
|
||||
export const getMainCategoryDetail = (props) => (dispatch, getState) => {
|
||||
const { patnrId, prdtId } = props;
|
||||
const onSuccess = (response) => {
|
||||
console.log("getMainCategoryDetail onSuccess ", response.data);
|
||||
|
||||
dispatch({
|
||||
type: types.GET_PRODUCT_DETAIL,
|
||||
payload: response.data.data,
|
||||
});
|
||||
};
|
||||
|
||||
const onFail = (error) => {
|
||||
console.error("getMainCategoryDetail onFail", error);
|
||||
};
|
||||
|
||||
TAxios(
|
||||
dispatch,
|
||||
getState,
|
||||
"get",
|
||||
URLS.GET_PRODUCT_DETAIL,
|
||||
{ patnrId, prdtId },
|
||||
{},
|
||||
onSuccess,
|
||||
onFail
|
||||
);
|
||||
};
|
||||
export const getSubCategory = (params, key) => (dispatch, getState) => {
|
||||
const { lgCatCd, patnrIdList, tabType, pageSize, pageNo, filterType } =
|
||||
params;
|
||||
|
||||
@@ -28,3 +28,61 @@ export const getBestSeller = () => (dispatch, getState) => {
|
||||
onFail
|
||||
);
|
||||
};
|
||||
|
||||
// Detail 옵션상품 정보 조회 IF-LGSP-319
|
||||
export const getProductGroup = (props) => (dispatch, getState) => {
|
||||
const { patnrId, prdtId } = props;
|
||||
|
||||
const onSuccess = (response) => {
|
||||
console.log("getProductGroup onSuccess", response.data);
|
||||
|
||||
dispatch({
|
||||
type: types.GET_PRODUCT_GROUP,
|
||||
payload: response.data.data,
|
||||
});
|
||||
};
|
||||
|
||||
const onFail = (error) => {
|
||||
console.error("getProductGroup onFail", error);
|
||||
};
|
||||
|
||||
TAxios(
|
||||
dispatch,
|
||||
getState,
|
||||
"get",
|
||||
URLS.GET_PRODUCT_GROUP,
|
||||
{ patnrId, prdtId },
|
||||
{},
|
||||
onSuccess,
|
||||
onFail
|
||||
);
|
||||
};
|
||||
|
||||
// Detail 옵션상품 정보 조회 IF-LGSP-320
|
||||
export const getProductOption = (props) => (dispatch, getState) => {
|
||||
const { patnrId, prdtId } = props;
|
||||
|
||||
const onSuccess = (response) => {
|
||||
console.log("getProductOption onSuccess", response.data);
|
||||
|
||||
dispatch({
|
||||
type: types.GET_PRODUCT_OPTION,
|
||||
payload: response.data.data,
|
||||
});
|
||||
};
|
||||
|
||||
const onFail = (error) => {
|
||||
console.error("getProductOption onFail", error);
|
||||
};
|
||||
|
||||
TAxios(
|
||||
dispatch,
|
||||
getState,
|
||||
"get",
|
||||
URLS.GET_PRODUCT_OPTION,
|
||||
{ patnrId, prdtId },
|
||||
{},
|
||||
onSuccess,
|
||||
onFail
|
||||
);
|
||||
};
|
||||
|
||||
@@ -34,7 +34,8 @@ export const URLS = {
|
||||
|
||||
//product controller
|
||||
GET_PRODUCT_BESTSELLER: "/lgsp/v1/product/bestSeller.lge",
|
||||
|
||||
GET_PRODUCT_GROUP: "/lgsp/v1/product/group.lge",
|
||||
GET_PRODUCT_OPTION: "/lgsp/v1/product/option.lge",
|
||||
//my-page controller
|
||||
GET_MY_RECOMMANDED_KEYWORD: "/lgsp/v1/mypage/reckeyword.lge",
|
||||
GET_MY_FAQ_INFO: "/lgsp/v1/mypage/support/faq.lge",
|
||||
@@ -47,12 +48,13 @@ export const URLS = {
|
||||
//main controller
|
||||
GET_SUB_CATEGORY: "/lgsp/v1/main/subcategory.lge",
|
||||
GET_TOP20_SHOW: "/lgsp/v1/main/top/show.lge",
|
||||
GET_PRODUCT_DETAIL: "/lgsp/v1/main/category/product/detail.lge",
|
||||
|
||||
//event controller
|
||||
GET_WELCOME_EVENT_INFO: "/lgsp/v1/event/event.lge",
|
||||
};
|
||||
const getRicCode = (country, ricCodeSetting) =>{
|
||||
if(ricCodeSetting !== 'system'){
|
||||
const getRicCode = (country, ricCodeSetting) => {
|
||||
if (ricCodeSetting !== "system") {
|
||||
return ricCodeSetting;
|
||||
}
|
||||
if (country == "US") {
|
||||
@@ -63,27 +65,28 @@ const getRicCode = (country, ricCodeSetting) =>{
|
||||
return "ruc";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
export const getUrl = (getState, endStr) => {
|
||||
const serverHOST = getState().common.appStatus.serverHOST;
|
||||
const {serverType, ricCodeSetting} = getState().localSettings;
|
||||
if(!serverHOST){
|
||||
console.error('getUrl: Not supported. Host is missing');
|
||||
const { serverType, ricCodeSetting } = getState().localSettings;
|
||||
if (!serverHOST) {
|
||||
console.error("getUrl: Not supported. Host is missing");
|
||||
return "";
|
||||
}
|
||||
let sdpURL = serverHOST.split(".")[0];
|
||||
let countryCode = "", ricCode="";
|
||||
let countryCode = "",
|
||||
ricCode = "";
|
||||
if (sdpURL.indexOf("-") > 0) {
|
||||
countryCode = sdpURL.split("-")[1];
|
||||
} else {
|
||||
countryCode = sdpURL;
|
||||
}
|
||||
ricCode = getRicCode(countryCode, ricCodeSetting);
|
||||
if(!ricCode){
|
||||
if (!ricCode) {
|
||||
return "";
|
||||
}
|
||||
sdpURL = sdpURL.toLowerCase();
|
||||
if(serverType !== 'system'){
|
||||
if (serverType !== "system") {
|
||||
sdpURL = serverType;
|
||||
}
|
||||
let newUrl = "";
|
||||
|
||||
@@ -32,7 +32,7 @@ export default function TBody({
|
||||
{children}
|
||||
</TScroller>
|
||||
) : (
|
||||
{ children }
|
||||
children
|
||||
)}
|
||||
</Container>
|
||||
);
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import React from "react";
|
||||
|
||||
import css from "./THeader.module.less";
|
||||
import classNames from "classnames";
|
||||
|
||||
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||
|
||||
import css from "./THeader.module.less";
|
||||
|
||||
const Container = SpotlightContainerDecorator(
|
||||
{ enterTo: "last-focused" },
|
||||
"div"
|
||||
);
|
||||
|
||||
export default function THeader({ title, className }) {
|
||||
export default function THeader({ title, className, onBackButton, onClick }) {
|
||||
return (
|
||||
<Container className={classNames(css.tHeader, className)}>
|
||||
{onBackButton && <button className={css.button} onClick={onClick} />}
|
||||
<div className={css.title}>{title}</div>
|
||||
</Container>
|
||||
);
|
||||
|
||||
@@ -15,4 +15,18 @@
|
||||
font-size: 42px;
|
||||
margin-left: 61px;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.button {
|
||||
.size(@w: 60px, @h: 60px);
|
||||
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-image: url('../../../assets/button/60x60/btn-60-bk-back-nor@3x.png');
|
||||
border: none;
|
||||
margin-right: -49px;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { types } from "../actions/actionTypes";
|
||||
const initialState = {
|
||||
subCategoryData: {},
|
||||
top20ShowData: {},
|
||||
productData: {},
|
||||
};
|
||||
|
||||
export const mainReducer = (state = initialState, action) => {
|
||||
@@ -18,6 +19,11 @@ export const mainReducer = (state = initialState, action) => {
|
||||
...state,
|
||||
top20ShowData: action.payload,
|
||||
};
|
||||
case types.GET_PRODUCT_DETAIL:
|
||||
return {
|
||||
...state,
|
||||
productData: action.payload.product[0],
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
|
||||
@@ -11,7 +11,16 @@ export const productReducer = (state = initialState, action) => {
|
||||
...state,
|
||||
bestSellerData: action.payload,
|
||||
};
|
||||
|
||||
case types.GET_PRODUCT_OPTION:
|
||||
return {
|
||||
...state,
|
||||
prdtOptInfo: action.payload.prdtOptInfo,
|
||||
};
|
||||
case types.GET_PRODUCT_GROUP:
|
||||
return {
|
||||
...state,
|
||||
groupInfo: action.payload.groupInfo,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ export const panel_names = {
|
||||
CART_PANEL: "cartpanel",
|
||||
FEATURED_BRANDS_PANEL: "featuredbrandspanel",
|
||||
WELCOME_EVENT_PANEL: "welcomeeventpanel",
|
||||
DETAIL_PANEL: "detailpanel",
|
||||
|
||||
// error
|
||||
ERROR_PANEL: "errorpanel",
|
||||
|
||||
47
com.twin.app.shoptime/src/views/DetailPanel/ItemDetail.jsx
Normal file
47
com.twin.app.shoptime/src/views/DetailPanel/ItemDetail.jsx
Normal file
@@ -0,0 +1,47 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
import { getMainCategoryDetail } from "../../actions/mainActions";
|
||||
import TBody from "../../components/TBody/TBody";
|
||||
import THeader from "../../components/THeader/THeader";
|
||||
import TPanel from "../../components/TPanel/TPanel";
|
||||
import css from "./ItemDetail.module.less";
|
||||
import ItemImage from "./layout/ItemImage";
|
||||
import OptionList from "./layout/OptionList";
|
||||
|
||||
export default function ItemDetail() {
|
||||
const [selectedPatnrId, setSelectedPatnrId] = useState(1);
|
||||
const [selectedPardtId, setSelectedPardtId] = useState("A523924");
|
||||
|
||||
const [productData, setProductData] = useState();
|
||||
const data = useSelector((state) => state.main.productData);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
getMainCategoryDetail({
|
||||
patnrId: selectedPatnrId,
|
||||
prdtId: selectedPardtId,
|
||||
})
|
||||
);
|
||||
}, [dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
setProductData(data);
|
||||
// console.log("#groupInfo", productData);
|
||||
}, [data, productData]);
|
||||
return (
|
||||
<TPanel isTabActivated={false}>
|
||||
<THeader
|
||||
className={css.header}
|
||||
title={productData?.prdtNm}
|
||||
onBackButton
|
||||
/>
|
||||
<TBody className={css.container} scrollable={false}>
|
||||
<ItemImage productData={productData} />
|
||||
<OptionList />
|
||||
</TBody>
|
||||
</TPanel>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
@import '../../style/CommonStyle.module.less';
|
||||
@import "../../style/utils.module.less";
|
||||
|
||||
|
||||
.header {
|
||||
> div {
|
||||
.font(@fontFamily: @baseFontBold, @fontSize: 30px) !important;
|
||||
}
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 90px;
|
||||
background-color: #f2f2f2;
|
||||
align-items: center;
|
||||
color: #333333;
|
||||
padding: 0 0 0 60px;
|
||||
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
import Image from "@enact/sandstone/Image";
|
||||
import Spottable from "@enact/spotlight/Spottable";
|
||||
|
||||
import css from "./Indicator.module.less";
|
||||
|
||||
const SpottableComponent = Spottable("button");
|
||||
|
||||
export default function Indicator({ images }) {
|
||||
const [selectedImage, setSelectedImage] = useState(null);
|
||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (images && images.length > 0) {
|
||||
setSelectedImage(images[0]);
|
||||
}
|
||||
}, [images]);
|
||||
|
||||
const handlePrevClick = () => {
|
||||
setSelectedImage((prevSelectedImage) => {
|
||||
const currentIndex = images.indexOf(prevSelectedImage);
|
||||
return currentIndex === 0
|
||||
? images[images.length - 1]
|
||||
: images[currentIndex - 1];
|
||||
});
|
||||
};
|
||||
|
||||
const handleNextClick = () => {
|
||||
setSelectedImage((prevSelectedImage) => {
|
||||
const currentIndex = images.indexOf(prevSelectedImage);
|
||||
return currentIndex === images.length - 1
|
||||
? images[0]
|
||||
: images[currentIndex + 1];
|
||||
});
|
||||
};
|
||||
|
||||
const handleItemClick = (image) => {
|
||||
setSelectedImage(image);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={css.Wrap}>
|
||||
<div>
|
||||
{images && <img src={selectedImage} alt="" className={css.thumbnail} />}
|
||||
</div>
|
||||
<div>
|
||||
<SpottableComponent
|
||||
onClick={handlePrevClick}
|
||||
className={css.upButton}
|
||||
/>
|
||||
{images &&
|
||||
images
|
||||
.slice(0, 3)
|
||||
.map((image, index) => (
|
||||
<Image
|
||||
key={index}
|
||||
src={image}
|
||||
alt={""}
|
||||
onClick={() => handleItemClick(image)}
|
||||
selected={selectedIndex === index}
|
||||
className={css.image}
|
||||
/>
|
||||
))}
|
||||
<SpottableComponent
|
||||
className={css.downButton}
|
||||
onClick={handleNextClick}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
@import '../../../style/CommonStyle.module.less';
|
||||
@import "../../../style/utils.module.less";
|
||||
|
||||
.Wrap {
|
||||
margin: 30px 0 0 10px;
|
||||
height: 560px;
|
||||
display: flex;
|
||||
|
||||
|
||||
.thumbnail {
|
||||
.size(@w: 560px, @h: 560px);
|
||||
border: solid 1px #dadada;
|
||||
// background-color: #fff;
|
||||
//margin: 30px 10px 10px 0 ;
|
||||
background-color: red;
|
||||
|
||||
}
|
||||
|
||||
.upButton {
|
||||
.size(@w: 144px , @h: 48px);
|
||||
border: none;
|
||||
margin-bottom: 4px;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
background-image: url('../../../../assets/button/etc/btn-bk-up-nor.svg');
|
||||
|
||||
}
|
||||
|
||||
.downButton {
|
||||
.size(@w: 144px , @h: 48px);
|
||||
border: none;
|
||||
margin-top: 10px;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
background-image: url('../../../../assets/button/etc/btn-bk-down-nor.svg');
|
||||
}
|
||||
|
||||
|
||||
|
||||
.image {
|
||||
margin: 0;
|
||||
// border: solid 1px #dadada;
|
||||
.size(@w: 140px , @h: 140px);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
import Spottable from "@enact/spotlight/Spottable";
|
||||
|
||||
import { $L } from "../../../utils/helperMethods";
|
||||
import Indicator from "../components/Indicator";
|
||||
import css from "../layout/ItemImage.module.less";
|
||||
|
||||
const SpottableComponent = Spottable("div");
|
||||
|
||||
export default function ItemImage({ productData }) {
|
||||
const [images, setImages] = useState();
|
||||
|
||||
useEffect(() => {
|
||||
if (productData) {
|
||||
setImages(productData?.imgUrls);
|
||||
}
|
||||
}, [productData, images]);
|
||||
|
||||
return (
|
||||
<SpottableComponent className={css.Wrap}>
|
||||
<Indicator images={images} />
|
||||
<div className={css.order}>
|
||||
<div>{$L("Call to Order")}</div>
|
||||
<div className={css.icon}>
|
||||
<span />
|
||||
<div>{productData?.orderPhnNo}</div>
|
||||
</div>
|
||||
</div>
|
||||
</SpottableComponent>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
@import '../../../style/CommonStyle.module.less';
|
||||
@import "../../../style/utils.module.less";
|
||||
|
||||
.Wrap {
|
||||
padding-left: 120px;
|
||||
.size(@w: 894px, @h: 930px);
|
||||
.thumbnail {
|
||||
.size(@w: 560px, @h: 560px);
|
||||
border: solid 1px #dadada;
|
||||
background-color: #fff;
|
||||
margin: 30px 10px 10px 0 ;
|
||||
}
|
||||
|
||||
.order {
|
||||
.font(@fontFamily: @baseFontBold, @fontSize: 30px);
|
||||
.size(@w: 560px, @h: 68px);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
line-height: 68px;
|
||||
background-color: #f2f2f2;
|
||||
|
||||
> div {
|
||||
padding: 0 33px 0 30px;
|
||||
}
|
||||
}
|
||||
.icon {
|
||||
display: flex;
|
||||
> span {
|
||||
.size(@w: 42px, @h: 42px);
|
||||
background-image: url("../../../../assets/icon/ic-gr-call.svg");
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
|
||||
margin: 13px 0 0 4px ;
|
||||
}
|
||||
}
|
||||
|
||||
.indicator{
|
||||
// display: flex;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import React from "react";
|
||||
|
||||
import Spottable from "@enact/spotlight/Spottable";
|
||||
|
||||
import css from "./OptionList.module.less";
|
||||
|
||||
const SpottableComponent = Spottable("div");
|
||||
export default function OptionList() {
|
||||
return <SpottableComponent className={css.Wrap}></SpottableComponent>;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
@import '../../../style/CommonStyle.module.less';
|
||||
@import '../../../style/utils.module.less';
|
||||
|
||||
.Wrap {
|
||||
.size(@w: 1026px, @h: 930px);
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
Reference in New Issue
Block a user