[checkoutpanel] 배송지, 청구지 주소 변경 시 실시간 세금 계산, loadingpanel 추가

This commit is contained in:
hyunwoo93.cha
2024-05-21 10:05:59 +09:00
parent d433017273
commit 126ab252cd
9 changed files with 112 additions and 118 deletions

View File

@@ -1,6 +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';
// 회원 체크아웃 정보 조회 IF-LGSP-345 // 회원 체크아웃 정보 조회 IF-LGSP-345
export const getMyInfoCheckoutInfo = (props) => (dispatch, getState) => { export const getMyInfoCheckoutInfo = (props) => (dispatch, getState) => {
@@ -85,12 +86,16 @@ 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,

View File

@@ -1,6 +1,6 @@
import appinfo from "../../webos-meta/appinfo.json"; import appinfo from '../../webos-meta/appinfo.json';
import * as Config from "../utils/Config"; import * as Config from '../utils/Config';
import LS2Request from "./LS2Request"; import LS2Request from './LS2Request';
export const getSystemInfo = ( export const getSystemInfo = (
parameters, parameters,
@@ -125,7 +125,10 @@ export const launchMembershipAppNew = (
subscribe: false, subscribe: false,
parameters: { parameters: {
category: "MembershipApp", category: "MembershipApp",
params: { query: "", appReturn: { appId: window.PalmSystem.identifier ?? appinfo.id } }, params: {
query: "",
appReturn: { appId: window.PalmSystem.identifier ?? appinfo.id },
},
}, },
onSuccess, onSuccess,
onFailure, onFailure,
@@ -150,7 +153,10 @@ export const launchMembershipApp = (
subscribe: false, subscribe: false,
parameters: { parameters: {
id: "com.webos.app.membership", id: "com.webos.app.membership",
params: { query: "", appReturn: { appId: window.PalmSystem.identifier ?? appinfo.id } }, params: {
query: "",
appReturn: { appId: window.PalmSystem.identifier ?? appinfo.id },
},
}, },
onSuccess, onSuccess,
onFailure, onFailure,

View File

@@ -1,4 +1,4 @@
import LS2Request from "./LS2Request"; import LS2Request from './LS2Request';
export const getConnectionStatus = ({ onSuccess, onFailure, onComplete }) => { export const getConnectionStatus = ({ onSuccess, onFailure, onComplete }) => {
if (process.env.REACT_APP_MODE === "DEBUG") { if (process.env.REACT_APP_MODE === "DEBUG") {

View File

@@ -4,6 +4,7 @@ const initialState = {
checkoutData: {}, checkoutData: {},
taxInfosData: {}, taxInfosData: {},
infoForCheckoutData: {}, infoForCheckoutData: {},
taxAndSHData: {},
}; };
export const checkoutReducer = (state = initialState, action) => { export const checkoutReducer = (state = initialState, action) => {

View File

@@ -13,6 +13,7 @@ import {
getMyInfoCheckoutInfo, getMyInfoCheckoutInfo,
getTaxInfos, getTaxInfos,
} from '../../actions/checkoutActions'; } from '../../actions/checkoutActions';
import { changeAppStatus } from '../../actions/commonActions';
import { popPanel } from '../../actions/panelActions'; import { popPanel } from '../../actions/panelActions';
import TBody from '../../components/TBody/TBody'; import TBody from '../../components/TBody/TBody';
import THeader from '../../components/THeader/THeader'; import THeader from '../../components/THeader/THeader';
@@ -42,7 +43,6 @@ export default function CheckOutPanel() {
const infoForCheckoutData = useSelector( const infoForCheckoutData = useSelector(
(state) => state.checkout?.infoForCheckoutData (state) => state.checkout?.infoForCheckoutData
); );
const [orderSideBarOpen, setOrderSideBarOpen] = useState(false); const [orderSideBarOpen, setOrderSideBarOpen] = useState(false);
const [offerSideBarOpen, setOfferSideBarOpen] = useState(false); const [offerSideBarOpen, setOfferSideBarOpen] = useState(false);
@@ -70,23 +70,23 @@ export default function CheckOutPanel() {
dispatch( dispatch(
getTaxInfos({ getTaxInfos({
mbrNo: userInfo, mbrNo: userInfo,
bilAddrSno: infoForCheckoutData?.bilAddrSno || 206, bilAddrSno: infoForCheckoutData?.bilAddrSno,
dlvrAddrSno: infoForCheckoutData?.dlvrAddrSno || 3003, dlvrAddrSno: infoForCheckoutData?.dlvrAddrSno,
reqCheckoutTaxInfoItemList: [ reqCheckoutTaxInfoItemList: [
{ {
cpnSno: null, cpnSno: null,
dcAmt: null, dcAmt: null,
frgtTaxCd: productData?.[0].frgtTaxCd || "FR020900", frgtTaxCd: productData?.[0].frgtTaxCd,
patnrId: productData?.[0].patnrId || "11", patnrId: productData?.[0].patnrId,
prdtId: productData?.[0].prdtId || "7127927", prdtId: productData?.[0].prdtId,
prodPrc: productData?.[0].price3 || 9.99, prodPrc: productData?.[0].price3,
prodQty: productData?.[0].prodQty || 1, prodQty: productData?.[0].prodQty,
taxCd: productData?.[0].taxCd || "P0000000", taxCd: productData?.[0].taxCd,
}, },
], ],
}) })
); );
}, [dispatch]); }, [dispatch, infoForCheckoutData, productData]);
const onBackClick = useCallback(() => { const onBackClick = useCallback(() => {
dispatch(popPanel()); dispatch(popPanel());

View File

@@ -36,9 +36,9 @@ export default function CheckOutTerms() {
Spotlight.focus("tab-0"); Spotlight.focus("tab-0");
}, [introTermsData, dispatch]); }, [introTermsData, dispatch]);
const description = $L( const description =
"Check out more LIVE SHOWS and enjoy Shopping via your TV at Shop Times special prices by agreeing to the LG TV Shopping Terms and Conditions" $L(`Check out more LIVE SHOWS and enjoy Shopping via your TV \n at Shop Times special prices by agreeing to the LG TV
); Shopping Terms and Conditions`);
const checkOut = [$L("Terms of Purchase"), $L("Privacy Policy")]; const checkOut = [$L("Terms of Purchase"), $L("Privacy Policy")];
return ( return (

View File

@@ -11,6 +11,7 @@ import SpotlightContainerDecorator
from '@enact/spotlight/SpotlightContainerDecorator'; from '@enact/spotlight/SpotlightContainerDecorator';
import { updateSelectedShippingAddr } from '../../../actions/checkoutActions'; import { updateSelectedShippingAddr } from '../../../actions/checkoutActions';
import { changeAppStatus } from '../../../actions/commonActions';
import TCheckBox from '../../../components/TCheckBox/TCheckBox'; import TCheckBox from '../../../components/TCheckBox/TCheckBox';
import TScroller from '../../../components/TScroller/TScroller'; import TScroller from '../../../components/TScroller/TScroller';
import CheckOutContainer from './CheckOutContainer'; import CheckOutContainer from './CheckOutContainer';

View File

@@ -1,7 +1,4 @@
import React, { import React, { useCallback } from 'react';
useCallback,
useState,
} from 'react';
import { import {
useDispatch, useDispatch,
@@ -12,16 +9,13 @@ import SpotlightContainerDecorator
from '@enact/spotlight/SpotlightContainerDecorator'; from '@enact/spotlight/SpotlightContainerDecorator';
import Spottable from '@enact/spotlight/Spottable'; import Spottable from '@enact/spotlight/Spottable';
import { updateSelectedShippingAddr } from '../../../actions/checkoutActions';
import TButton from '../../../components/TButton/TButton'; import TButton from '../../../components/TButton/TButton';
import { $L } from '../../../utils/helperMethods'; import { $L } from '../../../utils/helperMethods';
import BillingAddressCard from '../components/BillingAddressCard'; import BillingAddressCard from '../components/BillingAddressCard';
import PaymentCard from '../components/PaymentCard'; import PaymentCard from '../components/PaymentCard';
import ShippingAddressCard from '../components/ShippingAddressCard'; import ShippingAddressCard from '../components/ShippingAddressCard';
import Subject from '../components/Subject'; import Subject from '../components/Subject';
import FixedSideBar from './FixedSideBar.jsx';
import css from './InformationContainer.module.less'; import css from './InformationContainer.module.less';
import OrderItemsSideBar from './OrderItemsSideBar';
const Container = SpotlightContainerDecorator( const Container = SpotlightContainerDecorator(
{ enterTo: "last-focused" }, { enterTo: "last-focused" },
@@ -38,6 +32,8 @@ export default function InformationContainer({
const checkoutData = useSelector((state) => state.checkout?.checkoutData); const checkoutData = useSelector((state) => state.checkout?.checkoutData);
const handleButtonClick = useCallback(() => {}, []);
return ( return (
<> <>
<Container className={css.container}> <Container className={css.container}>

View File

@@ -1,16 +1,25 @@
import React, { useCallback, useEffect, useMemo, useState } from "react"; import React, {
useCallback,
useEffect,
useMemo,
useState,
} from 'react';
import { useDispatch, useSelector } from "react-redux"; import {
useDispatch,
useSelector,
} from 'react-redux';
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator"; import SpotlightContainerDecorator
from '@enact/spotlight/SpotlightContainerDecorator';
import { registerDevice } from "../../../actions/deviceActions"; import { registerDevice } from '../../../actions/deviceActions';
import { getHomeTerms } from "../../../actions/homeActions"; import { getHomeTerms } from '../../../actions/homeActions';
import { setPurchaseTermsAgree } from "../../../actions/orderActions"; import { setPurchaseTermsAgree } from '../../../actions/orderActions';
import TButton from "../../../components/TButton/TButton"; import TButton from '../../../components/TButton/TButton';
import TCheckBox from "../../../components/TCheckBox/TCheckBox"; import TCheckBox from '../../../components/TCheckBox/TCheckBox';
import { $L } from "../../../utils/helperMethods"; import { $L } from '../../../utils/helperMethods';
import css from "./SummaryContainer.module.less"; import css from './SummaryContainer.module.less';
const Container = SpotlightContainerDecorator( const Container = SpotlightContainerDecorator(
{ enterTo: "last-focused" }, { enterTo: "last-focused" },
@@ -22,7 +31,9 @@ export default function SummaryContainer({ userInfo }) {
const { productList } = useSelector((state) => state.checkout.checkoutData); const { productList } = useSelector((state) => state.checkout.checkoutData);
const termsData = useSelector((state) => state.home.termsData); const termsData = useSelector((state) => state.home.termsData);
const { checkoutTermsAgree } = useSelector((state) => state.common); const taxInfosData = useSelector((state) => state.checkout?.taxInfosData);
console.log("chw", taxInfosData);
const checkoutTermsData = useMemo( const checkoutTermsData = useMemo(
() => () =>
@@ -50,58 +61,68 @@ export default function SummaryContainer({ userInfo }) {
currSign: "", currSign: "",
currSignLoc: "", currSignLoc: "",
}); });
const [agreements, setAgreements] = useState(() => {
const initialAgreements = {};
checkoutTermsData.forEach(({ id }) => { const itemSetting = useCallback(
initialAgreements[id] = checkoutTermsAgree; (productList) => {
}); if (!productList || productList.length === 0) return;
return initialAgreements; let itemCnt = 0; // 상품 함계
}); let shCnt = 0; // 배송비 합계
let couponCnt = 0; // 쿠폰 할인 합계
let itemsTotal = 0; // 상품 + 배송비
let taxCnt = 0; // 세금 합계
let itemsTaxTotal = 0; // itemsTotal + tax
let estimatedTotal = 0; // itemsTotal + tax - couponCnt
const itemSetting = useCallback((productList) => { productList.forEach((info) => {
if (!productList || productList.length === 0) return; const itemPrice = info.price3 || info.price2;
itemCnt += itemPrice * parseInt(info.prodQty, 10);
let itemCnt = 0; // 상품 함계 shCnt += parseFloat(info.shippingCharge || 0);
let shCnt = 0; // 배송비 합계
let couponCnt = 0; // 쿠폰 할인 합계
let itemsTotal = 0; // 상품 + 배송비
let taxCnt = 0; // 세금 합계
let itemsTaxTotal = 0; // itemsTotal + tax
let estimatedTotal = 0; // itemsTotal + tax - couponCnt
productList.forEach((info) => { if (info.prdtCoupon && info.prdtCoupon.length > 0) {
const itemPrice = info.price3 || info.price2; couponCnt += info.prdtCoupon.reduce(
itemCnt += itemPrice * parseInt(info.prodQty, 10); (acc, coupon) => acc + parseFloat(coupon.discountAmount || 0),
0
);
}
});
shCnt += parseFloat(info.shippingCharge || 0); if (
taxInfosData.totDlvrAmt !== null &&
if (info.prdtCoupon && info.prdtCoupon.length > 0) { taxInfosData.totDlvrAmt !== undefined
couponCnt += info.prdtCoupon.reduce( ) {
(acc, coupon) => acc + parseFloat(coupon.discountAmount || 0), shCnt = taxInfosData.totDlvrAmt;
0
);
} }
});
itemsTotal = itemCnt + shCnt; if (
itemsTaxTotal = itemsTotal + taxCnt; taxInfosData.billing?.taxTotAmt !== null &&
estimatedTotal = itemsTaxTotal - couponCnt; taxInfosData.billing?.taxTotAmt !== undefined
) {
taxCnt = taxInfosData.billing.taxTotAmt;
}
setSummary((prevSummary) => ({ itemsTotal = itemCnt + shCnt;
...prevSummary, itemsTaxTotal = itemsTotal + taxCnt;
itemPrice: itemCnt.toFixed(2), estimatedTotal = itemsTaxTotal - couponCnt;
shPrice: shCnt.toFixed(2),
couponPrice: couponCnt.toFixed(2), setSummary((prevSummary) => ({
itemsTotal: itemsTotal.toFixed(2), ...prevSummary,
taxTotal: taxCnt.toFixed(2), itemPrice: itemCnt.toFixed(2),
itemsTaxTotal: itemsTaxTotal.toFixed(2), shPrice: shCnt.toFixed(2),
estimatedTotal: estimatedTotal.toFixed(2), couponPrice: couponCnt.toFixed(2),
currSign: productList[0]?.currSign || "", itemsTotal: itemsTotal.toFixed(2),
currSignLoc: productList[0]?.currSignLoc || "", taxTotal: taxCnt.toFixed(2),
})); itemsTaxTotal: itemsTaxTotal.toFixed(2),
}, []); estimatedTotal: estimatedTotal.toFixed(2),
currSign: productList[0]?.currSign || "",
currSignLoc: productList[0]?.currSignLoc || "",
}));
console.log("chw", summary);
},
[taxInfosData]
);
useEffect(() => { useEffect(() => {
if (productList && productList.length > 0) { if (productList && productList.length > 0) {
@@ -118,40 +139,9 @@ export default function SummaryContainer({ userInfo }) {
{ name: "Your Coupon Savings", value: summary.couponPrice }, { name: "Your Coupon Savings", value: summary.couponPrice },
]; ];
useEffect(() => {
const initialAgreements = Object.fromEntries(
checkoutTermsData.map(({ id }) => [id, checkoutTermsAgree])
);
setAgreements(initialAgreements);
}, [checkoutTermsData, checkoutTermsAgree]);
const handleAgreeCheck = useCallback((trmsId) => {
setAgreements((prev) => ({ ...prev, [trmsId]: !prev[trmsId] }));
}, []);
const handleClickOrder = useCallback(() => { const handleClickOrder = useCallback(() => {
const allAgreed = Object.values(agreements).every((agreed) => agreed); console.log("success");
}, []);
if (checkoutTermsAgree) {
if (allAgreed) {
console.log("success");
} else {
console.error("failed (please check checkbox)");
}
} else {
if (allAgreed) {
const agreeTerms = Object.keys(agreements).filter(
(trmsId) => agreements[trmsId]
);
dispatch(
setPurchaseTermsAgree({ mbrNo: userInfo, termsList: agreeTerms })
);
console.log("success");
} else {
console.error("failed (not agree terms)");
}
}
}, [dispatch, agreements, userInfo, checkoutTermsAgree]);
return ( return (
<Container className={css.container}> <Container className={css.container}>
@@ -186,11 +176,6 @@ export default function SummaryContainer({ userInfo }) {
<div className={css.bottom}> <div className={css.bottom}>
{checkoutTermsData.map((term, index) => ( {checkoutTermsData.map((term, index) => (
<div className={css.checkboxWrap} key={index}> <div className={css.checkboxWrap} key={index}>
<TCheckBox
className={css.checkbox}
selected={agreements[term.id]}
onToggle={() => handleAgreeCheck(term.id)}
/>
<div className={css.contents}>{term.content}</div> <div className={css.contents}>{term.content}</div>
</div> </div>
))} ))}