384 lines
9.7 KiB
JavaScript
384 lines
9.7 KiB
JavaScript
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
|
|
|
import classNames from "classnames";
|
|
import { useDispatch, useSelector } from "react-redux";
|
|
|
|
import Alert from "@enact/sandstone/Alert";
|
|
import Spotlight from "@enact/spotlight";
|
|
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
|
import Spottable from "@enact/spotlight/Spottable";
|
|
|
|
import defaultImageItem from "../../../assets/images/img-thumb-empty-product@3x.png";
|
|
import { cancelFocusElement, focusElement } from "../../actions/commonActions";
|
|
import { SpotlightIds } from "../../utils/SpotlightIds";
|
|
import CustomImage from "../CustomImage/CustomImage";
|
|
import TButton from "../TButton/TButton";
|
|
import css from "../TPopUp/TPopUp.module.less";
|
|
import { $L } from "../../utils/helperMethods";
|
|
|
|
const Container = SpotlightContainerDecorator(
|
|
{ enterTo: "default-element" },
|
|
Spottable("div")
|
|
);
|
|
|
|
const OptionContainer = SpotlightContainerDecorator(
|
|
{ enterTo: "last-focused" },
|
|
Spottable("ul")
|
|
);
|
|
|
|
const ButtonContainer = SpotlightContainerDecorator("div");
|
|
const ButtonContainerNegative = SpotlightContainerDecorator(
|
|
{ defaultElement: `[data-spotlight-id="${"tPopupBtn2"}"]` },
|
|
"div"
|
|
);
|
|
const SpottableComponent = Spottable("li");
|
|
const SpottableDiv = Spottable("div");
|
|
|
|
const KINDS = [
|
|
"textPopup",
|
|
"termsPopup",
|
|
"introTermsPopup",
|
|
"optionPopup",
|
|
"eventBannerPopup",
|
|
"supportPopup",
|
|
"exitPopup",
|
|
"couponPopup",
|
|
"mobileSendPopup",
|
|
"qrPopup",
|
|
"checkoutTermsPopup",
|
|
"scrollPopup",
|
|
"watchPopup",
|
|
"setPinCodePopup",
|
|
"descriptionPopup",
|
|
"errorPopup",
|
|
"orderDetailPopup",
|
|
"returnExchangePopup",
|
|
"orderCancelPopup",
|
|
"cancelConfirmPopup",
|
|
"trackPackagePopup",
|
|
"optionalAgreement",
|
|
"normal",
|
|
];
|
|
|
|
export default function TPopUp({
|
|
kind,
|
|
children,
|
|
onExit,
|
|
onClick,
|
|
currentPage,
|
|
onRightClick,
|
|
onLeftClick,
|
|
itemLength,
|
|
onClose,
|
|
hasButton,
|
|
hasText,
|
|
hasOnClose = false,
|
|
hasIndicator,
|
|
hasLogo,
|
|
hasThumbnail,
|
|
thumbnail,
|
|
logo,
|
|
className,
|
|
button1Text,
|
|
button2Text,
|
|
open,
|
|
title,
|
|
text,
|
|
type = "overlay",
|
|
options,
|
|
optionClick,
|
|
selectedIndex,
|
|
spotlightId,
|
|
onSpotlightRight,
|
|
...rest
|
|
}) {
|
|
const dispatch = useDispatch();
|
|
const popupVisible = useSelector((state) => state.common.popup.popupVisible);
|
|
const httpHeader = useSelector((state) => state.common.httpHeader);
|
|
|
|
useEffect(() => {
|
|
if (popupVisible) {
|
|
if (spotlightId) {
|
|
const timerId = setTimeout(() => {
|
|
Spotlight.focus(spotlightId);
|
|
}, 0);
|
|
|
|
return () => {
|
|
clearTimeout(timerId);
|
|
};
|
|
}
|
|
const timerId = setTimeout(() => {
|
|
Spotlight.focus(SpotlightIds.TPOPUP);
|
|
}, 0);
|
|
|
|
return () => {
|
|
clearTimeout(timerId);
|
|
};
|
|
}
|
|
}, [spotlightId, popupVisible]);
|
|
|
|
useEffect(() => {
|
|
if (KINDS.indexOf(kind) < 0) {
|
|
console.error("TPopUp kind error");
|
|
}
|
|
}, [kind]);
|
|
|
|
const ButtonContainerComp = useMemo(() => {
|
|
return kind === "exitPopup" ? ButtonContainerNegative : ButtonContainer;
|
|
}, [kind]);
|
|
|
|
// optionalAgreement
|
|
// 자동으로 Yes/No 버튼 텍스트 설정
|
|
|
|
const finalButton1Text = useMemo(() => {
|
|
if (kind === "optionalAgreement" && !button1Text) {
|
|
return "Yes";
|
|
}
|
|
return button1Text;
|
|
}, [kind, button1Text]);
|
|
|
|
const finalButton2Text = useMemo(() => {
|
|
if (kind === "optionalAgreement" && !button2Text) {
|
|
return "No";
|
|
}
|
|
return button2Text;
|
|
}, [kind, button2Text]);
|
|
|
|
// optionalAgreement일 경우 항상 버튼 표시
|
|
const shouldShowButtons = useMemo(() => {
|
|
return hasButton || kind === "optionalAgreement";
|
|
}, [hasButton, kind]);
|
|
|
|
//-------------------------------------------------------
|
|
|
|
const _onClick = useCallback(
|
|
(e) => {
|
|
if (onClick) {
|
|
onClick(e);
|
|
} else if (kind === "exitPopup") _onExit();
|
|
else _onClose();
|
|
},
|
|
[onClick, kind, _onExit, _onClose]
|
|
);
|
|
|
|
const _optionClick = useCallback(
|
|
(e, idx) => {
|
|
if (optionClick) {
|
|
optionClick(e, idx);
|
|
}
|
|
},
|
|
[optionClick]
|
|
);
|
|
|
|
const _onExit = useCallback(
|
|
(e) => {
|
|
if (onExit) {
|
|
onExit(e);
|
|
}
|
|
},
|
|
[onExit]
|
|
);
|
|
|
|
const _onClose = useCallback(
|
|
(e) => {
|
|
if (onClose) {
|
|
onClose(e);
|
|
}
|
|
},
|
|
[onClose]
|
|
);
|
|
const selectedOptClick = useCallback(
|
|
(index, optionStockQuantity) => (e) => {
|
|
if (optionStockQuantity && optionStockQuantity <= 0) {
|
|
return;
|
|
}
|
|
_optionClick(index);
|
|
},
|
|
[_optionClick]
|
|
);
|
|
|
|
const _onLeftClick = useCallback(
|
|
(e) => {
|
|
if (onLeftClick) {
|
|
onLeftClick(e);
|
|
}
|
|
},
|
|
[onLeftClick]
|
|
);
|
|
const _onRightClick = useCallback(
|
|
(e) => {
|
|
if (onRightClick) {
|
|
onRightClick(e);
|
|
}
|
|
},
|
|
[onRightClick]
|
|
);
|
|
|
|
const _onSpotlightRight = useCallback(
|
|
(e) => {
|
|
if (onSpotlightRight) {
|
|
onSpotlightRight(e);
|
|
}
|
|
},
|
|
[onSpotlightRight]
|
|
);
|
|
|
|
const ariaHidden = useMemo(() => {
|
|
const deviceCountryCode = httpHeader?.["X-Device-Country"] || "";
|
|
if (deviceCountryCode === "US") {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}, [httpHeader]);
|
|
return (
|
|
<Alert
|
|
open={open}
|
|
onClose={_onClose}
|
|
type={type}
|
|
className={classNames(
|
|
css.tPopUp,
|
|
css[kind],
|
|
title && css.title,
|
|
text && css.text,
|
|
hasButton && css.hasButton,
|
|
kind === "optionalTermsConfirmPopup" && css.bottomPopup,
|
|
className ? className : null
|
|
)}
|
|
aria-hidden={ariaHidden}
|
|
>
|
|
<Container className={css.info} spotlightId={SpotlightIds.TPOPUP}>
|
|
{hasThumbnail && thumbnail && (
|
|
<div className={css.thumbnail}>
|
|
<CustomImage
|
|
src={thumbnail}
|
|
fallbackSrc={defaultImageItem}
|
|
alt="thumbnail"
|
|
/>
|
|
</div>
|
|
)}
|
|
{hasText && (
|
|
<div className={css.textLayer}>
|
|
{title && (
|
|
<div className={css.title} aria-label={title + "heading 1"}>
|
|
{title}
|
|
</div>
|
|
)}
|
|
{hasLogo && logo !== null && (
|
|
<span>
|
|
<CustomImage
|
|
src={logo}
|
|
fallbackSrc={defaultImageItem}
|
|
alt="logo"
|
|
/>
|
|
</span>
|
|
)}
|
|
{text && (
|
|
<div className={css.text} aria-label={text}>
|
|
{text}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
{options && (
|
|
<OptionContainer
|
|
className={classNames(
|
|
css.optionLayer,
|
|
options.length >= 5 ? css.optionScroll : null
|
|
)}
|
|
>
|
|
{options.map((option, index) => {
|
|
const { prodOptCval, optImgUrl, optPrc, optStkQty, optNm } =
|
|
option;
|
|
const optStock = Number(optStkQty);
|
|
|
|
return (
|
|
<SpottableComponent
|
|
{...rest}
|
|
className={classNames(
|
|
css.option,
|
|
optStkQty > 0 &&
|
|
index === selectedIndex &&
|
|
css.selectedOption,
|
|
|
|
index == selectedIndex && css.focused,
|
|
optStkQty <= 0 && css.optionSoldOut
|
|
)}
|
|
spotlightId={`selectedOptionBtn-${index}`}
|
|
onClick={selectedOptClick(index, optStkQty)}
|
|
key={`option: ${index}`}
|
|
aria-label={optNm ? optNm : prodOptCval}
|
|
spotlightDisabled={optStkQty && optStkQty <= 0}
|
|
>
|
|
{optImgUrl && (
|
|
<CustomImage
|
|
src={optImgUrl}
|
|
className={css.img}
|
|
fallbackSrc={defaultImageItem}
|
|
alt="optionImg"
|
|
/>
|
|
)}
|
|
<div className={css.optionItem}>
|
|
<span>{optNm ? optNm : prodOptCval}</span>
|
|
{optStkQty && optStkQty <= 0 && (
|
|
<span>{$L("SOLD OUT")}</span>
|
|
)}
|
|
</div>
|
|
|
|
{optPrc && optStock !== 0 && `($${optPrc})`}
|
|
</SpottableComponent>
|
|
);
|
|
})}
|
|
</OptionContainer>
|
|
)}
|
|
{children}
|
|
{hasIndicator && (
|
|
<>
|
|
{currentPage !== 0 && (
|
|
<SpottableDiv
|
|
className={css.leftBtn}
|
|
onClick={_onLeftClick}
|
|
aria-label="Move to left"
|
|
role="button"
|
|
></SpottableDiv>
|
|
)}
|
|
{currentPage !== itemLength - 1 && (
|
|
<SpottableDiv
|
|
className={css.rightBtn}
|
|
onClick={_onRightClick}
|
|
aria-label="Move to Right"
|
|
role="button"
|
|
></SpottableDiv>
|
|
)}
|
|
</>
|
|
)}
|
|
{shouldShowButtons && (
|
|
<ButtonContainerComp className={css.buttonContainer}>
|
|
{finalButton1Text && (
|
|
<TButton
|
|
spotlightId="tPopupBtn1"
|
|
onClick={_onClick}
|
|
role="button"
|
|
ariaLabel={finalButton1Text}
|
|
onSpotlightRight={_onSpotlightRight}
|
|
>
|
|
{finalButton1Text}
|
|
</TButton>
|
|
)}
|
|
{finalButton2Text && (
|
|
<TButton
|
|
spotlightId="tPopupBtn2"
|
|
onClick={onClose}
|
|
role="button"
|
|
ariaLabel={finalButton2Text}
|
|
>
|
|
{finalButton2Text}
|
|
</TButton>
|
|
)}
|
|
</ButtonContainerComp>
|
|
)}
|
|
</Container>
|
|
</Alert>
|
|
);
|
|
}
|