[checkoutpanel] pinCode 포커스 처리 및 에러코드 별 분기처리 / qr팝업 추가 / SHA256 암호화

This commit is contained in:
hyunwoo93.cha
2024-05-28 21:26:42 +09:00
parent af76e562f2
commit 535fcd6a6a
14 changed files with 319 additions and 122 deletions

View File

@@ -16,6 +16,8 @@
"@enact/ui": "^3.3.0", "@enact/ui": "^3.3.0",
"@enact/webos": "^3.3.0", "@enact/webos": "^3.3.0",
"axios": "^0.21.1", "axios": "^0.21.1",
"crypto-js": "^4.2.0",
"google-libphonenumber": "^3.2.34",
"ilib": "^14.3.0", "ilib": "^14.3.0",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"qrcode": "^1.5.3", "qrcode": "^1.5.3",
@@ -675,6 +677,11 @@
"integrity": "sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA==", "integrity": "sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA==",
"deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js." "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js."
}, },
"node_modules/crypto-js": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
},
"node_modules/csstype": { "node_modules/csstype": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@@ -908,6 +915,14 @@
"process": "^0.11.10" "process": "^0.11.10"
} }
}, },
"node_modules/google-libphonenumber": {
"version": "3.2.34",
"resolved": "https://registry.npmjs.org/google-libphonenumber/-/google-libphonenumber-3.2.34.tgz",
"integrity": "sha512-CLwkp0lZvMywh6dCh0T3Fm8XsfJhLAupc8AECwYkJNQBPW8wQPrv/tV0oFKCs8FMw+pTQyNPZoycgBzYjqtTZQ==",
"engines": {
"node": ">=0.10"
}
},
"node_modules/graceful-fs": { "node_modules/graceful-fs": {
"version": "4.2.11", "version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
@@ -2409,6 +2424,11 @@
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
"integrity": "sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA==" "integrity": "sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA=="
}, },
"crypto-js": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
},
"csstype": { "csstype": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@@ -2587,6 +2607,11 @@
"process": "^0.11.10" "process": "^0.11.10"
} }
}, },
"google-libphonenumber": {
"version": "3.2.34",
"resolved": "https://registry.npmjs.org/google-libphonenumber/-/google-libphonenumber-3.2.34.tgz",
"integrity": "sha512-CLwkp0lZvMywh6dCh0T3Fm8XsfJhLAupc8AECwYkJNQBPW8wQPrv/tV0oFKCs8FMw+pTQyNPZoycgBzYjqtTZQ=="
},
"graceful-fs": { "graceful-fs": {
"version": "4.2.11", "version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",

View File

@@ -40,6 +40,7 @@
"@enact/ui": "^3.3.0", "@enact/ui": "^3.3.0",
"@enact/webos": "^3.3.0", "@enact/webos": "^3.3.0",
"axios": "^0.21.1", "axios": "^0.21.1",
"crypto-js": "^4.2.0",
"google-libphonenumber": "^3.2.34", "google-libphonenumber": "^3.2.34",
"ilib": "^14.3.0", "ilib": "^14.3.0",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",

View File

@@ -135,6 +135,7 @@ export const types = {
GET_TAX_INFOS: "GET_TAX_INFOS", GET_TAX_INFOS: "GET_TAX_INFOS",
UPDATE_SELECTED_SHIPPING_ADDR: "UPDATE_SELECTED_SHIPPING_ADDR", UPDATE_SELECTED_SHIPPING_ADDR: "UPDATE_SELECTED_SHIPPING_ADDR",
UPDATE_SELECTED_BILLING_ADDR: "UPDATE_SELECTED_BILLING_ADDR", UPDATE_SELECTED_BILLING_ADDR: "UPDATE_SELECTED_BILLING_ADDR",
CHECKOUT_DATA_RESET: "CHECKOUT_DATA_RESET",
// order actions // order actions
SET_PURCHASE_TERMS_AGREE: "SET_PURCHASE_TERMS_AGREE", SET_PURCHASE_TERMS_AGREE: "SET_PURCHASE_TERMS_AGREE",

View File

@@ -1,7 +1,7 @@
import { URLS } from '../api/apiConfig'; import { URLS } from "../api/apiConfig";
import { TAxios } from '../api/TAxios'; import { TAxios } from "../api/TAxios";
import { types } from './actionTypes'; import { types } from "./actionTypes";
import { changeAppStatus } from './commonActions'; import { changeAppStatus } from "./commonActions";
// 회원 체크아웃 정보 조회 IF-LGSP-345 // 회원 체크아웃 정보 조회 IF-LGSP-345
export const getMyInfoCheckoutInfo = (props) => (dispatch, getState) => { export const getMyInfoCheckoutInfo = (props) => (dispatch, getState) => {
@@ -86,16 +86,12 @@ export const getTaxInfos = (props) => (dispatch, getState) => {
type: types.GET_TAX_INFOS, type: types.GET_TAX_INFOS,
payload: response.data.data, payload: response.data.data,
}); });
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
}; };
const onFail = (error) => { const onFail = (error) => {
console.error("getTaxInfos onFail: ", error); console.error("getTaxInfos onFail: ", error);
}; };
dispatch(changeAppStatus({ showLoadingPanel: { show: true, type: "wait" } }));
TAxios( TAxios(
dispatch, dispatch,
getState, getState,
@@ -130,3 +126,7 @@ export const updateSelectedBillingAddr = (bilAddrSno) => ({
type: types.UPDATE_SELECTED_BILLING_ADDR, type: types.UPDATE_SELECTED_BILLING_ADDR,
payload: bilAddrSno, payload: bilAddrSno,
}); });
export const resetCheckoutData = () => ({
type: types.CHECKOUT_DATA_RESET,
});

View File

@@ -1,22 +1,28 @@
import { URLS } from '../api/apiConfig'; import { URLS } from "../api/apiConfig";
import { TAxios } from '../api/TAxios'; import { TAxios } from "../api/TAxios";
import { types } from './actionTypes'; import { types } from "./actionTypes";
import { changeAppStatus } from "./commonActions";
// 회원 등록카드 PIN CODE 입력 체크 IF-LGSP-336 // 회원 등록카드 PIN CODE 입력 체크 IF-LGSP-336
export const getMyInfoCardPincodeCheck = (params) => (dispatch, getState) => { export const getMyInfoCardPincodeCheck = (params) => (dispatch, getState) => {
const { mbrNo, pinCd } = params; const { mbrNo, pinCd } = params;
dispatch(changeAppStatus({ showLoadingPanel: { show: true, type: "wait" } }));
const onSuccess = (response) => { const onSuccess = (response) => {
console.log("getMyInfoCardPincodeCheck onSuccess ", response.data); console.log("getMyInfoCardPincodeCheck onSuccess ", response);
dispatch({ dispatch({
type: types.GET_MY_INFO_CARD_PINCODE_CHECK, type: types.GET_MY_INFO_CARD_PINCODE_CHECK,
payload: response.data.data, payload: response.data,
}); });
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
}; };
const onFail = (error) => { const onFail = (error) => {
console.error("getMyInfoCardPincodeCheck onFail ", error); console.error("getMyInfoCardPincodeCheck onFail ", error);
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
}; };
TAxios( TAxios(

View File

@@ -40,6 +40,7 @@ const KINDS = [
"checkoutTermsPopup", "checkoutTermsPopup",
"scrollPopup", "scrollPopup",
"watchPopup", "watchPopup",
"setPinCodePopup",
]; ];
export default function TPopUp({ export default function TPopUp({

View File

@@ -504,3 +504,25 @@
} }
} }
} }
.setPinCodePopup {
.default-style();
.info {
.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;
}
}
}
}

View File

@@ -1,4 +1,4 @@
import { types } from '../actions/actionTypes'; import { types } from "../actions/actionTypes";
const initialState = { const initialState = {
checkoutData: {}, checkoutData: {},
@@ -39,6 +39,9 @@ export const checkoutReducer = (state = initialState, action) => {
}, },
}; };
case types.CHECKOUT_DATA_RESET:
return initialState;
default: default:
return state; return state;
} }

View File

@@ -60,6 +60,7 @@ export const ACTIVE_POPUP = {
eventPopup: "eventPopup", eventPopup: "eventPopup",
smsPopup: "smsPopup", smsPopup: "smsPopup",
alertPopup: "alertPopup", alertPopup: "alertPopup",
setPinCodePopup: "setPinCodePopup",
}; };
export const DEBUG_VIDEO_SUBTITLE_TEST = false; export const DEBUG_VIDEO_SUBTITLE_TEST = false;
export const AUTO_SCROLL_DELAY = 600; export const AUTO_SCROLL_DELAY = 600;

View File

@@ -17,4 +17,7 @@ export const SpotlightIds = {
PLAYER_SLIDER: "playerslider", PLAYER_SLIDER: "playerslider",
LIST_PLAYER: "list_player", LIST_PLAYER: "list_player",
LIST_PLAYER2: "list_player2", LIST_PLAYER2: "list_player2",
//pin Code Popup
PINCODE_CONTAINER: "pincodeContainer",
}; };

View File

@@ -8,6 +8,7 @@ import Spotlight from "@enact/spotlight";
import { import {
getMyInfoCheckoutInfo, getMyInfoCheckoutInfo,
getTaxInfos, getTaxInfos,
resetCheckoutData,
} from "../../actions/checkoutActions"; } from "../../actions/checkoutActions";
import { changeAppStatus } from "../../actions/commonActions"; import { changeAppStatus } from "../../actions/commonActions";
import { getShoptimeTerms } from "../../actions/empActions"; import { getShoptimeTerms } from "../../actions/empActions";
@@ -47,6 +48,7 @@ export default function CheckOutPanel() {
const cardInfo = useSelector( const cardInfo = useSelector(
(state) => state.checkout?.checkoutData.cardInfo (state) => state.checkout?.checkoutData.cardInfo
); );
const taxInfosData = useSelector((state) => state.checkout?.taxInfosData);
const [orderSideBarOpen, setOrderSideBarOpen] = useState(false); const [orderSideBarOpen, setOrderSideBarOpen] = useState(false);
const [offerSideBarOpen, setOfferSideBarOpen] = useState(false); const [offerSideBarOpen, setOfferSideBarOpen] = useState(false);
@@ -73,33 +75,41 @@ export default function CheckOutPanel() {
], ],
}) })
); );
}, [dispatch, userNumber, checkoutPanelInfo]);
useEffect(() => {
return () => {
dispatch(resetCheckoutData());
};
}, [dispatch]); }, [dispatch]);
useEffect(() => { useEffect(() => {
dispatch( if (infoForCheckoutData && productData) {
getTaxInfos({ dispatch(
mbrNo: userNumber, getTaxInfos({
bilAddrSno: infoForCheckoutData?.bilAddrSno, mbrNo: userNumber,
dlvrAddrSno: infoForCheckoutData?.dlvrAddrSno, bilAddrSno: infoForCheckoutData?.bilAddrSno,
reqCheckoutTaxInfoItemList: [ dlvrAddrSno: infoForCheckoutData?.dlvrAddrSno,
{ reqCheckoutTaxInfoItemList: [
cpnSno: null, {
dcAmt: null, cpnSno: null,
frgtTaxCd: productData?.[0].frgtTaxCd, dcAmt: null,
patnrId: productData?.[0].patnrId, frgtTaxCd: productData?.[0].frgtTaxCd,
prdtId: productData?.[0].prdtId, patnrId: productData?.[0].patnrId,
prodPrc: productData?.[0].price3, prdtId: productData?.[0].prdtId,
prodQty: productData?.[0].prodQty, prodPrc: productData?.[0].price3,
taxCd: productData?.[0].taxCd, prodQty: productData?.[0].prodQty,
}, taxCd: productData?.[0].taxCd,
], },
}) ],
); })
}, [dispatch, infoForCheckoutData, productData]); );
}
}, [dispatch, infoForCheckoutData, productData, userNumber]);
useEffect(() => { useEffect(() => {
spotJob.current.start(() => { spotJob.current.start(() => {
Spotlight.focus("spotlightId_backBtn"); Spotlight.focus("spotlightId_placeOrderBtn");
}); });
return () => { return () => {
spotJob.current.stop(); spotJob.current.stop();
@@ -112,11 +122,15 @@ export default function CheckOutPanel() {
const toggleOrderSideBar = useCallback(() => { const toggleOrderSideBar = useCallback(() => {
setOrderSideBarOpen((prev) => !prev); setOrderSideBarOpen((prev) => !prev);
}, [orderSideBarOpen]); }, []);
const toggleOfferSideBar = useCallback(() => { const toggleOfferSideBar = useCallback(() => {
setOfferSideBarOpen((prev) => !prev); setOfferSideBarOpen((prev) => !prev);
}, [offerSideBarOpen]); }, []);
const onClosePopup = useCallback(() => {
setPlaceOrderPopup(false);
}, []);
return ( return (
<> <>
@@ -151,6 +165,7 @@ export default function CheckOutPanel() {
<TFullPopup <TFullPopup
open={placeOrderPopup} open={placeOrderPopup}
className={css.pinCodePopup} className={css.pinCodePopup}
onClose={onClosePopup}
noAnimation={true} noAnimation={true}
> >
<PinCodeInput setPlaceOrderPopup={setPlaceOrderPopup} /> <PinCodeInput setPlaceOrderPopup={setPlaceOrderPopup} />

View File

@@ -1,22 +1,22 @@
import React, { import React, { useCallback, useEffect, useState } from "react";
useCallback,
useState,
} from 'react';
import classNames from 'classnames'; import classNames from "classnames";
import { import CryptoJS from "crypto-js";
useDispatch, import { useDispatch, useSelector } from "react-redux";
useSelector,
} from 'react-redux';
import SpotlightContainerDecorator import Spotlight from "@enact/spotlight";
from '@enact/spotlight/SpotlightContainerDecorator'; import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import Spottable from '@enact/spotlight/Spottable'; import Spottable from "@enact/spotlight/Spottable";
import { getMyInfoCardPincodeCheck } from '../../../actions/pinCodeActions'; import { setHidePopup, setShowPopup } from "../../../actions/commonActions";
import TButton from '../../../components/TButton/TButton'; import { getMyInfoCardPincodeCheck } from "../../../actions/pinCodeActions";
import { $L } from '../../../utils/helperMethods'; import TButton from "../../../components/TButton/TButton";
import css from './PinCodeInput.module.less'; import TPopUp from "../../../components/TPopUp/TPopUp";
import TQRCode from "../../../components/TQRCode/TQRCode";
import * as Config from "../../../utils/Config";
import { $L } from "../../../utils/helperMethods";
import { SpotlightIds } from "../../../utils/SpotlightIds";
import css from "./PinCodeInput.module.less";
const PinCodeContainer = SpotlightContainerDecorator("div"); const PinCodeContainer = SpotlightContainerDecorator("div");
@@ -25,12 +25,39 @@ const SpottableButton = Spottable("div");
export default function PinCodeInput({ setPlaceOrderPopup }) { export default function PinCodeInput({ setPlaceOrderPopup }) {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { activePopup, popupVisible } = useSelector(
(state) => state.common.popup
);
const pinCodeDatas = useSelector((state) => state.pinCode.pinCodeData); const pinCodeDatas = useSelector((state) => state.pinCode.pinCodeData);
const userNumber = useSelector( const userNumber = useSelector(
(state) => state.common.appStatus.loginUserData.userNumber (state) => state.common.appStatus.loginUserData.userNumber
); );
const [pin, setPin] = useState(["", "", "", ""]); const [pin, setPin] = useState(["", "", "", ""]);
const [errorMsg, setErrorMsg] = useState("");
const [okClicked, setOkClicked] = useState(false);
useEffect(() => {
if (pinCodeDatas && pinCodeDatas.retCode !== 0 && okClicked) {
if (pinCodeDatas.data.pwdErrorCnt >= 3) {
dispatch(setShowPopup(Config.ACTIVE_POPUP.setPinCodePopup));
} else {
setErrorMsg($L("Your entries did not match. Please try again."));
}
}
}, [pinCodeDatas, dispatch, okClicked]);
useEffect(() => {
setOkClicked(false);
}, []);
useEffect(() => {
if (popupVisible && activePopup) {
setTimeout(() => {
Spotlight.focus("tPopupBtn1");
}, 0);
}
}, [popupVisible, activePopup]);
const handleDigitClick = useCallback( const handleDigitClick = useCallback(
(digit) => { (digit) => {
@@ -40,10 +67,6 @@ export default function PinCodeInput({ setPlaceOrderPopup }) {
if (nextIndex !== -1) { if (nextIndex !== -1) {
newPin[nextIndex] = digit; newPin[nextIndex] = digit;
setPin(newPin); setPin(newPin);
if (nextIndex === 3) {
console.log("chw", newPin.join(""));
}
} }
}, },
[pin] [pin]
@@ -66,49 +89,113 @@ export default function PinCodeInput({ setPlaceOrderPopup }) {
}, [setPlaceOrderPopup]); }, [setPlaceOrderPopup]);
const onClickConfirm = useCallback(() => { const onClickConfirm = useCallback(() => {
if (pin.includes("")) {
setErrorMsg($L("Please enter a PIN CODE."));
return;
}
setOkClicked(true);
const pinString = pin.join("");
const encryptedPin = CryptoJS.SHA256(pinString).toString();
dispatch( dispatch(
getMyInfoCardPincodeCheck({ getMyInfoCardPincodeCheck({
mbrNo: userNumber, mbrNo: userNumber,
pinCd: pin, pinCd: encryptedPin,
}) })
); );
}, [pin, userNumber, dispatch]);
const handleClickSetPinCode = useCallback(() => {
dispatch(setShowPopup(Config.ACTIVE_POPUP.qrPopup));
}, [dispatch]);
const handleCancelPopup = useCallback(() => {
dispatch(setHidePopup());
Spotlight.focus(SpotlightIds.PINCODE_CONTAINER);
}, [dispatch]); }, [dispatch]);
return ( return (
<PinCodeContainer className={css.pinCodeContainer}> <>
<h1 className={css.pinCodeTitle}>{$L("Enter PIN CODE")}</h1> <PinCodeContainer
<div className={css.pinCodeBoxes}> spotlightId={SpotlightIds.PINCODE_CONTAINER}
{pin.map((digit, index) => ( className={css.pinCodeContainer}
<div >
key={index} <h1 className={css.pinCodeTitle}>{$L("Enter PIN CODE")}</h1>
className={classNames(css.pinCodeBox, { <div className={css.pinCodeBoxes}>
[css.focused]: pin.findIndex((p) => p === "") === index, {pin.map((digit, index) => (
})} <div
> key={index}
{digit ? "•" : ""} className={classNames(css.pinCodeBox, {
</div> [css.focused]: pin.findIndex((p) => p === "") === index,
))} })}
</div> >
<div className={css.errMsg}>ERROR</div> {digit ? "•" : ""}
<div className={css.pinCodeDigits}> </div>
{[...Array(10).keys()].map((digit) => ( ))}
</div>
<div className={css.errMsg}>{errorMsg}</div>
<div className={css.pinCodeDigits}>
{[...Array(10).keys()].map((digit) => (
<SpottableButton
key={digit}
className={css.pinCodeDigit}
onClick={() => handleDigitClick(digit.toString())}
>
{digit}
</SpottableButton>
))}
<SpottableButton <SpottableButton
key={digit} className={classNames(css.pinCodeDigit, css.deleteKey)}
className={css.pinCodeDigit} onClick={handleBackspace}
onClick={() => handleDigitClick(digit.toString())} />
> </div>
{digit} <div className={css.buttonContainer}>
</SpottableButton> <TButton onClick={onClickCancel}>{$L("Cancel")}</TButton>
))} <TButton onClick={onClickConfirm}>{$L("OK")}</TButton>
<SpottableButton </div>
className={classNames(css.pinCodeDigit, css.deleteKey)} </PinCodeContainer>
onClick={handleBackspace}
{activePopup === Config.ACTIVE_POPUP.setPinCodePopup && (
<TPopUp
kind="setPinCodePopup"
open={popupVisible}
hasButton
button1Text={$L("OK")}
button2Text={$L("Cancel")}
onClick={handleClickSetPinCode}
onClose={handleCancelPopup}
hasText
text={$L(
"The number of PIN CODE errors has been exceeded and the PIN CODE cannot be used. Would you like to set a new PIN CODE?"
)}
/> />
</div> )}
<div className={css.buttonContainer}>
<TButton onClick={onClickCancel}>{$L("Cancel")}</TButton> {activePopup === Config.ACTIVE_POPUP.qrPopup && (
<TButton onClick={onClickConfirm}>{$L("OK")}</TButton> <TPopUp kind="qrPopup" open={popupVisible} onClose={handleCancelPopup}>
</div> <div className={css.popupContainer}>
</PinCodeContainer> <div className={css.header}>
<h3>{$L("QR CODE")}</h3>
</div>
<div className={css.qrcodeContainer}>
<div className={css.qrcode}>
<TQRCode text={"http://google.com"} width="360" height="360" />
</div>
<h3>
{$L(
"If you want to add or edit your address and payment information, please scan the QR CODE."
)}
</h3>
<TButton className={css.popupBtn} onClick={handleCancelPopup}>
{$L("CLOSE")}
</TButton>
</div>
</div>
</TPopUp>
)}
</>
); );
} }

View File

@@ -112,3 +112,44 @@
} }
} }
} }
.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;
}
}
}

View File

@@ -1,25 +1,12 @@
import React, { import React, { useCallback, useEffect, useState } from "react";
useCallback,
useEffect,
useMemo,
useState,
} from 'react';
import { import { useDispatch, useSelector } from "react-redux";
useDispatch,
useSelector,
} from 'react-redux';
import SpotlightContainerDecorator import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
from '@enact/spotlight/SpotlightContainerDecorator';
import { registerDevice } from '../../../actions/deviceActions'; import { changeAppStatus } from "../../../actions/commonActions";
import { getHomeTerms } from '../../../actions/homeActions'; import TButton from "../../../components/TButton/TButton";
import { setPurchaseTermsAgree } from '../../../actions/orderActions'; import css from "./SummaryContainer.module.less";
import TButton from '../../../components/TButton/TButton';
import TCheckBox from '../../../components/TCheckBox/TCheckBox';
import { $L } from '../../../utils/helperMethods';
import css from './SummaryContainer.module.less';
const Container = SpotlightContainerDecorator( const Container = SpotlightContainerDecorator(
{ enterTo: "last-focused" }, { enterTo: "last-focused" },
@@ -27,12 +14,13 @@ const Container = SpotlightContainerDecorator(
); );
const DEFAULT_SUMMARY = { const DEFAULT_SUMMARY = {
itemPrice: "0", itemPrice: "-",
shPrice: "0", shPrice: "-",
couponPrice: "0", couponPrice: "-",
itemsTotal: "0", itemsTotal: "-",
taxTotal: "0", taxTotal: "-",
itemsTaxTotal: "0", itemsTaxTotal: "-",
estimatedTotal: "-",
currSign: "", currSign: "",
currSignLoc: "", currSignLoc: "",
}; };
@@ -41,7 +29,6 @@ export default function SummaryContainer({ setPlaceOrderPopup }) {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { productList } = useSelector((state) => state.checkout.checkoutData); const { productList } = useSelector((state) => state.checkout.checkoutData);
const termsData = useSelector((state) => state.home.termsData);
const taxInfosData = useSelector((state) => state.checkout?.taxInfosData); const taxInfosData = useSelector((state) => state.checkout?.taxInfosData);
const [summary, setSummary] = useState(DEFAULT_SUMMARY); const [summary, setSummary] = useState(DEFAULT_SUMMARY);
@@ -51,7 +38,7 @@ export default function SummaryContainer({ setPlaceOrderPopup }) {
(productList) => { (productList) => {
if (!productList?.length) return; if (!productList?.length) return;
let itemCnt = 0; // 상품 let itemCnt = 0; // 상품
let shCnt = 0; // 배송비 합계 let shCnt = 0; // 배송비 합계
let couponCnt = 0; // 쿠폰 할인 합계 let couponCnt = 0; // 쿠폰 할인 합계
let itemsTotal = 0; // 상품 + 배송비 let itemsTotal = 0; // 상품 + 배송비
@@ -96,7 +83,7 @@ export default function SummaryContainer({ setPlaceOrderPopup }) {
currSignLoc: productList[0]?.currSignLoc || "", currSignLoc: productList[0]?.currSignLoc || "",
})); }));
}, },
[taxInfosData, auctProdYn] [taxInfosData, auctProdYn, dispatch]
); );
useEffect(() => { useEffect(() => {
@@ -116,7 +103,7 @@ export default function SummaryContainer({ setPlaceOrderPopup }) {
const handleClickOrder = useCallback(() => { const handleClickOrder = useCallback(() => {
setPlaceOrderPopup(true); setPlaceOrderPopup(true);
}, []); }, [setPlaceOrderPopup]);
return ( return (
<Container className={css.container}> <Container className={css.container}>
@@ -144,7 +131,7 @@ export default function SummaryContainer({ setPlaceOrderPopup }) {
) : ( ) : (
<div className={css.noticeBox}> <div className={css.noticeBox}>
<span className={css.noticeBoxText}> <span className={css.noticeBoxText}>
{$L("Purchased products will be paid at the final price.")} {"Purchased products will be paid at the final price."}
</span> </span>
</div> </div>
)} )}
@@ -165,7 +152,11 @@ export default function SummaryContainer({ setPlaceOrderPopup }) {
</div> </div>
</div> </div>
<div className={css.bottom}> <div className={css.bottom}>
<TButton className={css.tButton} onClick={handleClickOrder}> <TButton
className={css.tButton}
onClick={handleClickOrder}
spotlightId="spotlightId_placeOrderBtn"
>
{"PLACE ORDER"} {"PLACE ORDER"}
</TButton> </TButton>
</div> </div>