diff --git a/.DS_Store b/.DS_Store index 1f2f261d..588f6b30 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/com.twin.app.shoptime/assets/images/energyLabel/energyDetail.png b/com.twin.app.shoptime/assets/images/energyLabel/energyDetail.png new file mode 100644 index 00000000..20e269f4 Binary files /dev/null and b/com.twin.app.shoptime/assets/images/energyLabel/energyDetail.png differ diff --git a/com.twin.app.shoptime/assets/images/energyLabel/labelgradeA.png b/com.twin.app.shoptime/assets/images/energyLabel/labelgradeA.png new file mode 100644 index 00000000..cd787ec3 Binary files /dev/null and b/com.twin.app.shoptime/assets/images/energyLabel/labelgradeA.png differ diff --git a/com.twin.app.shoptime/assets/images/energyLabel/labelgradeB.png b/com.twin.app.shoptime/assets/images/energyLabel/labelgradeB.png new file mode 100644 index 00000000..1a81f117 Binary files /dev/null and b/com.twin.app.shoptime/assets/images/energyLabel/labelgradeB.png differ diff --git a/com.twin.app.shoptime/assets/images/energyLabel/labelgradeC.png b/com.twin.app.shoptime/assets/images/energyLabel/labelgradeC.png new file mode 100644 index 00000000..f714d944 Binary files /dev/null and b/com.twin.app.shoptime/assets/images/energyLabel/labelgradeC.png differ diff --git a/com.twin.app.shoptime/assets/images/energyLabel/labelgradeD.png b/com.twin.app.shoptime/assets/images/energyLabel/labelgradeD.png new file mode 100644 index 00000000..2d1ae568 Binary files /dev/null and b/com.twin.app.shoptime/assets/images/energyLabel/labelgradeD.png differ diff --git a/com.twin.app.shoptime/assets/images/energyLabel/labelgradeE.png b/com.twin.app.shoptime/assets/images/energyLabel/labelgradeE.png new file mode 100644 index 00000000..14cfa181 Binary files /dev/null and b/com.twin.app.shoptime/assets/images/energyLabel/labelgradeE.png differ diff --git a/com.twin.app.shoptime/assets/images/energyLabel/labelgradeF.png b/com.twin.app.shoptime/assets/images/energyLabel/labelgradeF.png new file mode 100644 index 00000000..39d88399 Binary files /dev/null and b/com.twin.app.shoptime/assets/images/energyLabel/labelgradeF.png differ diff --git a/com.twin.app.shoptime/assets/images/energyLabel/labelgradeG.png b/com.twin.app.shoptime/assets/images/energyLabel/labelgradeG.png new file mode 100644 index 00000000..53b648ac Binary files /dev/null and b/com.twin.app.shoptime/assets/images/energyLabel/labelgradeG.png differ diff --git a/com.twin.app.shoptime/assets/images/energyLabel/qr.png b/com.twin.app.shoptime/assets/images/energyLabel/qr.png new file mode 100644 index 00000000..49b4ef2c Binary files /dev/null and b/com.twin.app.shoptime/assets/images/energyLabel/qr.png differ diff --git a/com.twin.app.shoptime/src/components/TItemCard/TItemCard.module.less b/com.twin.app.shoptime/src/components/TItemCard/TItemCard.module.less index e8b70a9d..7645b708 100644 --- a/com.twin.app.shoptime/src/components/TItemCard/TItemCard.module.less +++ b/com.twin.app.shoptime/src/components/TItemCard/TItemCard.module.less @@ -1,6 +1,8 @@ @import "../../style/CommonStyle.module.less"; @import "../../style/utils.module.less"; +// moved into scoped blocks + /* horizontal */ .horizontal { display: flex; @@ -10,6 +12,14 @@ border: solid 1px @COLOR_GRAY02; background-color: @COLOR_WHITE; + .justForYouTag { + position: absolute; + width: 100px; + top: 40px; + right: 20px; + background-color: transparent; + } + .imageWrap { position: relative; .size(@w: 200px, @h: 200px); @@ -117,6 +127,14 @@ border: solid 1px @COLOR_GRAY02; background-color: @COLOR_WHITE; + .justForYouTag { + position: absolute; + width: 100px; + top: 40px; + right: 20px; + background-color: transparent; + } + .imageWrap { position: relative; .size(@w: 288px, @h: 288px); @@ -154,12 +172,46 @@ font-size: 36px; } } - + .flexBox { + display: flex; + flex-wrap: nowrap; + } + .labelImgBox { + display: flex; + flex-wrap: wrap; + align-content: flex-end; + width: 60px; + gap: 3px; + > div { + position: relative; + z-index: 100; + &:focus { + &::after { + .focused(@boxShadow: 22px, @borderRadius: 2px); + } + } + > img { + width: 60px; + height: 35px; + } + } + } .descWrap { .flex(@direction: column, @alignCenter: flex-start); width: 100%; - + &.labelBox { + width: calc(100% - 60px); + > p { + font-size: 27px; + &.priceInfo { + > span { + font-size: 16px; + } + } + } + } > div.title { + width: 100%; height: 64px; font-weight: bold; line-height: 1.33; @@ -315,8 +367,7 @@ margin-top: 11px; .size(@w: 508px, @h: 107px); - - .title { + &.title { margin-left: 15px; .size(@w: 430px, @h: 100px); .productNameTitle { @@ -414,4 +465,53 @@ .size(@w: 108px, @h: 48px); .position(@position: absolute, @top: 30px, @left: 30px); } + + .justForYouTag { + position: absolute; + width: 100px; + top: 40px; + right: 20px; + background-color: transparent; + } +} + +.popupContainer { + .header { + .size(@w: 780px , @h: 102px); + .flex(@display: flex, @justifyCenter: center, @alignCenter: center, @direction: row); + background-color: #e7ebef; + + > h3 { + font-size: 36px; + color: #222222; + font-weight: bold; + } + } + + .qrcodeContainer { + padding: 30px 0; + display: flex; + flex-direction: column; + align-items: center; + + .qrcode { + .size(@w: 360px , @h: 360px); + background-color: #ffffff; + border-radius: 12px; + box-shadow: 0 0 0 1px #dadada inset; + margin-bottom: 41px; + } + + > h3 { + display: flex; + text-align: center; + word-break: break-word; + line-height: 1.27; + } + + .popupBtn { + .size(@w: 300px , @h: 78px); + margin-top: 38px; + } + } } diff --git a/com.twin.app.shoptime/src/components/TItemCard/TitemCard.new.jsx b/com.twin.app.shoptime/src/components/TItemCard/TitemCard.new.jsx new file mode 100644 index 00000000..a41b888b --- /dev/null +++ b/com.twin.app.shoptime/src/components/TItemCard/TitemCard.new.jsx @@ -0,0 +1,473 @@ +import React, { + memo, + useCallback, + useEffect, + useMemo, + useState, +} from 'react'; + +import classNames from 'classnames'; +import { + useDispatch, + useSelector, +} from 'react-redux'; + +import Spottable from '@enact/spotlight/Spottable'; + +import energyDetail from '../../../assets/images/energyLabel/energyDetail.png'; +import energyLabelA from '../../../assets/images/energyLabel/labelgradeA.png'; +import energyLabelB from '../../../assets/images/energyLabel/labelgradeB.png'; +import energyLabelC from '../../../assets/images/energyLabel/labelgradeC.png'; +import energyLabelD from '../../../assets/images/energyLabel/labelgradeD.png'; +import energyLabelE from '../../../assets/images/energyLabel/labelgradeE.png'; +import energyLabelF from '../../../assets/images/energyLabel/labelgradeF.png'; +import energyLabelG from '../../../assets/images/energyLabel/labelgradeG.png'; +//에너지 라벨 +import qrImg from '../../../assets/images/energyLabel/qr.png'; +import defaultLogoImg + from '../../../assets/images/ic-tab-partners-default@3x.png'; +import defaultimgHorizontal + from '../../../assets/images/img-thumb-empty-hor@3x.png'; +import defaultImageItem + from '../../../assets/images/img-thumb-empty-product@3x.png'; +import defaultimgVertical + from '../../../assets/images/img-thumb-empty-ver@3x.png'; +import IcLiveShow from '../../../assets/images/tag/tag-liveshow.png'; +import { + setHidePopup, + setShowPopup, +} from '../../actions/commonActions'; +import { sendLogTotalRecommend } from '../../actions/logActions'; +import usePriceInfo from '../../hooks/usePriceInfo'; +import * as Config from '../../utils/Config'; +import { + $L, + getQRCodeUrl, + removeSpecificTags, +} from '../../utils/helperMethods'; +import CustomImage from '../CustomImage/CustomImage'; +import TPopUp from '../TPopUp/TPopUp'; +import css from './TItemCard.module.less'; + +const SpottableComponent = Spottable("div"); +const SpottableTemp = Spottable("div"); + +const TYPES = { + vertical: "vertical", + horizontal: "horizontal", + videoShow: "videoShow", +}; + +const IMAGETYPES = { + imgHorizontal: "imgHorizontal", + imgVertical: "imgVertical", +}; + +const STRING_CONF = { + SOLD_OUT: "SOLD OUT", +}; + +export const removeDotAndColon = (string) => { + return /[.:]/.test(string) ? string.replace(/[.:]/g, "") : string; +}; + +const parsePrice = (price) => { + return parseFloat(price?.replace(/[^0-9.-]+/g, "") || "0"); +}; + +export default memo(function TItemCardNew({ + children, + className, + disabled, + imageAlt, + imageSource, + imgType = IMAGETYPES.imgHorizontal, + logo, + logoDisplay = false, + isBestSeller = false, + isLive = false, + onBlur, + onClick, + onFocus, + onError, + offerInfo, + priceInfo, + productId, + productName, + catNm, + rank, + soldoutFlag, + spotlightId, + nonPosition = false, + type = TYPES.vertical, + firstLabel, + label, + lastLabel, + contextName, + messageId, + order, + patnerName, + brandName, + shelfId, + shelfLocation, + shelfTitle, + contentTitle, + category, + curationId, + curationTitle, + nowProductId, + nowCategory, + nowProductTitle, + contentId, + ...rest +}) { + const dispatch = useDispatch(); + const [defaultImage, setDefaultImage] = useState(null); + const [prdtId, setPrdtId] = useState(null); + const countryCode = useSelector((state) => state.common.httpHeader.cntry_cd); + const cursorVisible = useSelector( + (state) => state.common.appStatus.cursorVisible + ); + const { activePopup, popupVisible } = useSelector( + (state) => state.common.popup + ); + + const serverHOST = useSelector((state) => state.common.appStatus.serverHOST); + const serverType = useSelector((state) => state.localSettings.serverType); + + useEffect(() => { + if (!imageSource) { + if (type === "videoShow") { + setDefaultImage( + imgType === IMAGETYPES.imgHorizontal + ? defaultimgHorizontal + : defaultimgVertical + ); + } else { + setDefaultImage(defaultImageItem); + } + } + }, [imageSource, type, imgType]); + + const { originalPrice, discountedPrice, discountRate } = + usePriceInfo(priceInfo) || {}; + + const _onBlur = useCallback(() => { + if (onBlur) { + onBlur(); + } + }, [onBlur]); + + const _onClick = useCallback( + (e) => { + if (disabled) { + e.stopPropagation(); + return; + } + + if (onClick) { + onClick(e); + + if (contextName && messageId) { + const params = { + contextName: contextName, + messageId: messageId, + shelfLocation: shelfLocation, + shelfId: shelfId, + shelfTitle: shelfTitle, + productId: productId, + productTitle: productName, + nowProductId: nowProductId, + nowCategory: nowCategory, + nowProductTitle: nowProductTitle, + partner: patnerName, + brand: brandName, + price: originalPrice, + discount: discountRate, + location: order, + category: category ? category : catNm, + contentTitle: contentTitle, + curationId: curationId, + curationTitle: curationTitle, + }; + + dispatch(sendLogTotalRecommend(params)); + } + } + }, + [ + onClick, + disabled, + contextName, + messageId, + shelfLocation, + shelfId, + shelfTitle, + productId, + productName, + nowProductId, + nowCategory, + nowProductTitle, + patnerName, + brandName, + originalPrice, + discountRate, + order, + category, + catNm, + contentTitle, + curationId, + curationTitle, + dispatch, + ] + ); + + const _onFocus = useCallback(() => { + if (onFocus) { + onFocus(); + } + }, [onFocus]); + + const addDefaultImg = useCallback( + (e) => { + if (onError) { + onError(e); + } + }, + [onError] + ); + + const ariaLabel = useMemo(() => { + const soldOutText = soldoutFlag === "Y" ? "Sold Out " : ""; + const firstLabelText = firstLabel ? `${firstLabel} ` : ""; + const discountLabel = discountRate ? `${discountRate} discount, ` : ""; + const discountPriceLabel = discountRate + ? `Sale price ${discountedPrice}, ` + : ""; + + const parsedPrice = parsePrice(originalPrice); + const priceLabel = + parsedPrice === 0 + ? offerInfo + ? ` ${offerInfo}` + : "" + : originalPrice + ? ` Original price ${originalPrice}, ` + : ""; + + const productLabel = label || ""; + const lastLabelText = lastLabel || ""; + + return `${soldOutText}${firstLabelText}${discountLabel}${productName}${discountPriceLabel}${priceLabel}${productLabel}${lastLabelText}`; + }, [ + soldoutFlag, + firstLabel, + discountRate, + productName, + discountedPrice, + originalPrice, + offerInfo, + label, + lastLabel, + ]); + + const productNameDangerousHTML = useMemo(() => { + const sanitizedString = removeSpecificTags(productName); + return sanitizedString; + }, [productName]); + + const handleClosePopup = useCallback(() => { + dispatch(setHidePopup()); + }, [dispatch]); + + const { setupPinUrl } = useMemo(() => { + return getQRCodeUrl({ serverHOST, serverType }); + }, [serverHOST, serverType]); + + const onEnergyClick = useCallback( + (e, pId) => { + e.stopPropagation(); + setPrdtId(pId); + dispatch(setShowPopup(Config.ACTIVE_POPUP.energyPopup)); + }, + [dispatch] + ); + + return ( + <> + +
+ + {priceInfo && + discountRate && + Number(discountRate.replace("%", "")) > 4 && ( + {discountRate} + )} + {soldoutFlag && soldoutFlag === "Y" && ( +
+ {$L(STRING_CONF.SOLD_OUT)} +
+ )} + {isLive && ( + Live Show + )} +
+
+
+ 1000 + ? css.labelBox + : "" + )} + > + {logoDisplay && logo && ( +
+ +
+ )} + +
+

+

+ {children} + {priceInfo ? ( +

+ {parseFloat(originalPrice?.replace(/[^0-9.-]+/g, "") || "0") === + 0 ? ( + {offerInfo} + ) : discountRate ? ( + discountedPrice + ) : ( + originalPrice + )} + {discountRate && ( + {originalPrice} + )} +

+ ) : ( +

{offerInfo}

+ )} +
+ {originalPrice && + parseFloat(Number(originalPrice.replace("$", "").replace(",", ""))) > + 1000 ? ( +
+ onEnergyClick(e, productId)} + > + + + onEnergyClick(e, productId)} + > + + + onEnergyClick(e, productId)} + > + + +
+ ) : null} +
+ {isBestSeller && rank && ( +
+ {rank} +
+ )} +
+ {activePopup === Config.ACTIVE_POPUP.energyPopup && + prdtId === productId && ( + +
+ + +
+ +
+
+ {/* + +
+ +
+
*/} +
+
+ )} + + ); +}); + +export { IMAGETYPES, TYPES }; diff --git a/com.twin.app.shoptime/src/components/TPopUp/TPopUp.module.less b/com.twin.app.shoptime/src/components/TPopUp/TPopUp.module.less index 6522879e..f6d6c42c 100644 --- a/com.twin.app.shoptime/src/components/TPopUp/TPopUp.module.less +++ b/com.twin.app.shoptime/src/components/TPopUp/TPopUp.module.less @@ -69,7 +69,7 @@ // kind .introTermsPopup { - .default-style(); + .default-style(); .info { .size(@w: 1100px , @h: 564px); @@ -767,7 +767,7 @@ display: flex; flex-direction: column; font-weight: normal; - box-sizing: border-box; + box-sizing: border-box; border-radius: 4px; padding: 60px 57px 40px; @@ -812,3 +812,59 @@ } } } + +.energyPopup { + .default-style(@width: 960px); + .info { + background-color: #fff; + .textLayer { + .title { + width: 100%; + } + } + > div { + text-align: center; + + > span { + display: inline-flex; + padding: 30px 0px; + width: 412px; + height: 434px; + text-align: center; + margin-top: 30px; + margin-bottom: 30px; + margin-right: 10px; + background-color: #f3f3f3; + justify-content: center; + > img { + width: 185px; + } + > div { + display: flex; + align-items: flex-start; + > img { + justify-items: baseline; + width: 135px; + } + } + } + } + + .text { + padding: 0 60px; + min-height: 180px; + margin: 30px 0; + } + + .buttonContainer { + margin: 0 0 30px 0; + display: flex; + justify-content: center; + > div { + min-width: 240px; + height: 78px; + margin: 0 6px; + } + } + } +} diff --git a/com.twin.app.shoptime/src/utils/Config.js b/com.twin.app.shoptime/src/utils/Config.js index 62dc3e2d..923926b3 100644 --- a/com.twin.app.shoptime/src/utils/Config.js +++ b/com.twin.app.shoptime/src/utils/Config.js @@ -1,4 +1,4 @@ -import { $L } from "./helperMethods"; +import { $L } from './helperMethods'; export const SUPPORT_COUNTRIES = { US: "en", DE: "de", UK: "uk", RU: "ru" }; @@ -37,7 +37,7 @@ export const panel_names = { // debug DEBUG_PANEL: "debugpanel", VIDEO_TEST_PANEL: "videotestpanel", - + // user review USER_REVIEW_PANEL: "userreviewpanel", }; @@ -94,6 +94,7 @@ export const ACTIVE_POPUP = { introTermsPopup: "introTermsPopup", toast: "toast", optionalConfirm: "optionalConfirm", + energyPopup: "energyPopup", }; export const DEBUG_VIDEO_SUBTITLE_TEST = false; export const AUTO_SCROLL_DELAY = 600; diff --git a/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx b/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx index 266a3115..9ece1e91 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/SubCategory/SubCategory.jsx @@ -1,28 +1,38 @@ -import React, { memo, useCallback, useEffect, useState } from "react"; +import React, { + memo, + useCallback, + useEffect, + useState, +} from 'react'; -import { useDispatch, useSelector } from "react-redux"; +import { + useDispatch, + useSelector, +} from 'react-redux'; -import { SpotlightContainerDecorator } from "@enact/spotlight/SpotlightContainerDecorator"; -import Spottable from "@enact/spotlight/Spottable"; -import { setContainerLastFocusedElement } from "@enact/spotlight/src/container"; +import { + SpotlightContainerDecorator, +} from '@enact/spotlight/SpotlightContainerDecorator'; +import Spottable from '@enact/spotlight/Spottable'; +import { setContainerLastFocusedElement } from '@enact/spotlight/src/container'; -import { sendLogCuration } from "../../../actions/logActions"; -import { getSubCategory } from "../../../actions/mainActions"; -import { pushPanel } from "../../../actions/panelActions"; -import TItemCard from "../../../components/TItemCard/TItemCard"; -import TScroller from "../../../components/TScroller/TScroller"; -import usePrevious from "../../../hooks/usePrevious"; -import useScrollReset from "../../../hooks/useScrollReset"; -import useScrollTo from "../../../hooks/useScrollTo"; +import { sendLogCuration } from '../../../actions/logActions'; +import { getSubCategory } from '../../../actions/mainActions'; +import { pushPanel } from '../../../actions/panelActions'; +import TItemCardNew from '../../../components/TItemCard/TitemCard.new'; +import TScroller from '../../../components/TScroller/TScroller'; +import usePrevious from '../../../hooks/usePrevious'; +import useScrollReset from '../../../hooks/useScrollReset'; +import useScrollTo from '../../../hooks/useScrollTo'; import { LOG_CONTEXT_NAME, LOG_MESSAGE_ID, LOG_TP_NO, panel_names, -} from "../../../utils/Config"; -import { SpotlightIds } from "../../../utils/SpotlightIds"; -import CategoryNav from "../../HomePanel/SubCategory/CategoryNav/CategoryNav"; -import css from "../../HomePanel/SubCategory/SubCategory.module.less"; +} from '../../../utils/Config'; +import { SpotlightIds } from '../../../utils/SpotlightIds'; +import CategoryNav from '../../HomePanel/SubCategory/CategoryNav/CategoryNav'; +import css from '../../HomePanel/SubCategory/SubCategory.module.less'; const SpottableComponent = Spottable("div"); const Container = SpotlightContainerDecorator({ enterTo: null }, "div"); @@ -207,7 +217,7 @@ export default memo(function SubCategory({ handleShelfFocus(); } }, [handleShelfFocus]); - + console.log("###test pjh"); return ( { return ( -