////////////////////////////////////////////////////////////
const useQuery = () => {
return new URLSearchParams(useLocation().search);
};
const ProductCartMaster = (props) => {
const { } = props;
const { Card} = ReactBootstrap;
// --- 1. Khởi tạo States (Giữ nguyên toàn bộ) ---
const [barcode, setBarcode] = useState();
const [productSelected, setProductSelected] = useState();
const [baskets, setBaskets] = useState(null);
const [reloadPage, setReloadPage] = useState(_reload_page);
const [carts, setCarts] = useState([]);
const [transactionReturn, setTransactionReturn] = useState();
const [loading, setLoading] = useState(false);
const [showAllPromo, setShowAllPromo] = useState(false);
const [userInfo, setUserInfo] = useState();
const [shift, setShift] = useState();
const [member, setMember] = useState();
const [saleNumber, setSaleNumber] = useState();
const [content, setContent] = useState();
const [showCart, setShowCart] = useState();
const [returnNo, setReturnNo] = useState();
const [isMobile, setIsMobile] = useState(false);
// --- 2. Tối ưu các biến tính toán (Memoized Values) ---
const user_lang = useMemo(() => commonFunc.getCookies('user_lang') || 'vi', []);
// Config này truyền xuống rất nhiều con, cần useMemo để tránh render lại vô ích
const config = useMemo(() => ({
token: _token_encode,
lang: user_lang,
branch_no: (userInfo?.branch_no | 0)
}), [user_lang, userInfo?.branch_no]);
const isCashier = useMemo(() => {
const branchNo = parseInt(userInfo?.branch_no | 0);
return branchNo > 0 && branchNo < 1000;
}, [userInfo?.branch_no]);
// --- 3. Tối ưu Styles (Tránh tạo object mới khi re-render) ---
const styles = useMemo(() => ({
container: { display: 'flex', flexDirection: 'column', width: '100%' },
content: { display: 'flex', flexDirection: isMobile ? 'column' : 'row', width: '100%' },
productCart: {
flex: isMobile ? '0 0 100%' : '0 0 60%',
padding: '0px 10px 10px 10px',
display: showCart === true ? '' : 'none'
},
productInfoPOS: {
flex: isMobile ? '0 0 100%' : '0 0 40%',
padding: '0px 0px 10px 0px',
},
productInfoFull: {
flex: isMobile ? '0 0 100%' : '0 0 100%',
padding: '0px 0px 10px 0px',
}
}), [isMobile, showCart]);
// --- 4. Tối ưu Functions (Sử dụng useCallback) ---
const basketIconClick = useCallback(() => {
setShowCart(prevShowCart => !prevShowCart);
}, []);
const fetchUserInfo = async () => {
try {
setLoading(true);
const url = `/api/get-user-info`;
const resultObj = await commonApi.APIGETByURL(url, config);
if (resultObj.status === 200) {
let dataTmp = resultObj?.data;
setUserInfo(dataTmp);
}
} catch (e) {
setUserInfo(null);
console.log("ERROR get-user-info");
} finally {
setLoading(false);
}
};
const updateShoppingBasket=(cartCount = 3, onClickAction) => {
// 1. Tìm phần tử icon_shopping_basket
const basketIcon = document.getElementById('icon_shopping_basket');
const divBasketIcon = document.getElementById('div_shopping_basket');
if (basketIcon) {
// 2. Set display = '' (hiển thị lại nếu đang bị ẩn)
if (cartCount <= 0) {
divBasketIcon.style.cssText = 'display: none !important;float:right';
} else {
divBasketIcon.style.cssText = 'display: inline-flex !important;float:right';
}
// 3. Add actionClick nếu chưa có
// Sử dụng một thuộc tính custom trên DOM để đánh dấu đã gán sự kiện
if (!basketIcon.dataset.hasClickListener) {
basketIcon.addEventListener('click', function(e) {
console.log('Shopping basket clicked!');
if (typeof onClickAction === 'function') {
onClickAction();
}
});
// Đánh dấu để lần sau không add trùng
basketIcon.dataset.hasClickListener = 'true';
}
// 4. Tìm badge_shopping_basket và set caption (số lượng)
const badge = document.getElementById('badge_shopping_basket');
if (badge) {
badge.textContent = cartCount;
} else {
console.warn("Không tìm thấy phần tử badge_shopping_basket");
}
} else {
console.log("Không tìm thấy phần tử icon_shopping_basket");
}
}
const loadBasketsFromCookies = useCallback(() => {
let basketsCookie = commonFunc.getCookies('baskets');
if (basketsCookie) {
try {
let basketsObj = JSON.parse(basketsCookie);
setBaskets(basketsObj);
const totalQtyReduce = basketsObj.items.reduce((sum, item) => sum + item.qty, 0);
updateShoppingBasket(totalQtyReduce, basketIconClick);
} catch (e) {
console.log("Error parsing baskets cookie:", e);
setBaskets({ items: [] });
}
}
}, [basketIconClick]);
const handleChangeQty = useCallback((actionType, item_code, qty = 1, line_type = 'S') => {
setBaskets(prevBaskets => {
const updatedItems = prevBaskets?.items?.reduce((acc, item) => {
if (item.item_code === item_code && (item.line_type || 'S') === line_type) {
let newQty = 0;
if (item.line_type === 'R') {
newQty = actionType === '+' ? item.qty + qty : (item.qty - qty);
} else {
newQty = actionType === '+' ? item.qty + qty : Math.max(item.qty - qty, 0);
}
if (newQty !== 0 || item.line_type === 'R') {
acc.push({ ...item, qty: newQty });
} else {
return acc; // Loại bỏ item nếu qty = 0
}
} else {
acc.push(item);
}
return acc;
}, []);
const newBaskets = { ...prevBaskets, items: updatedItems };
// Logic cập nhật cookie đồng bộ
if (updatedItems.length === 0) {
commonFunc.setCookies('baskets', JSON.stringify({ items: [] }), undefined);
} else {
commonFunc.setCookies('baskets', JSON.stringify(newBaskets), undefined);
}
return newBaskets;
});
}, []);
const scrollToFirstPage = useCallback(() => {
const firstElement = document.getElementById('txtBarcode');
if (firstElement) {
firstElement.scrollIntoView({ behavior: 'smooth' });
}
}, []);
// --- 5. Effects (Quản lý vòng đời) ---
// Effect 1: Khởi tạo (Scripts, Resize, UserInfo)
useEffect(() => {
const scriptUrls = ['/static/e_comm/components/POS/product_cart/vat.js'];
if (window?.POSVAT == null && _extension === 'js') {
loadScripts(scriptUrls)
.then(() => console.log("All scripts loaded successfully."))
.catch(err => console.error(err));
}
if (userInfo == null) {
fetchUserInfo();
}
setContent(currentProductInfo);
const handleResize = () => {
setIsMobile(window.innerWidth < 1280);
};
window.addEventListener('resize', handleResize);
handleResize();
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
// Effect 2: Xử lý khi userInfo thay đổi
useEffect(() => {
if (!userInfo) return;
setContent(currentProductInfo);
loadBasketsFromCookies();
if (isCashier === true) {
setShowCart(true);
} else {
const urlParams = new URLSearchParams(window.location.search);
const showCartParam = urlParams.get('showCart');
setShowCart(showCartParam === 'true');
}
if (userInfo?.internal_user === true) {
let elm = document.getElementById('menuButton');
if (elm) elm.style.display = '';
}
}, [userInfo, isCashier, loadBasketsFromCookies]);
// Effect 3: Đồng bộ Badge giỏ hàng khi baskets thay đổi
useEffect(() => {
const totalQty = baskets?.items?.reduce((sum, item) => sum + item.qty, 0) || 0;
updateShoppingBasket(totalQty, basketIconClick);
}, [baskets, basketIconClick]);
// --- 6. Render Logic ---
if (saleNumber > 0) {
if (isCashier === true) {
return
{config?.lang === 'vi' ? ( <> Vui lòng đăng nhập ngay để sử dụng đầy đủ các chức năng của hệ thống. > ) : ( <> Please login now to access all system features. > )}