//////////////////////////////////////////////////////////// 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 ; } else { setBaskets(null); commonFunc.setCookies('baskets', {}, -1); window.location.href = `/mdc/transactions?type=external`; return null; // Tránh render tiếp } } return (
{/* Header section */} {(userInfo?.username !='guest') ? (
): ( showCart==true && {/* Icon cảnh báo nhỏ gọn */} {/* Câu thông báo tích hợp Link */}

{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. )}

) } {/* Main content section */}
{/* Promotions section */} {userInfo?.branch_no === "1000" && ( setShowAllPromo(!showAllPromo)} effectHover={false} styleHeader={{ padding: 3, background: '#e9439e', color: 'white' }} HeaderComponent={
All Promotions
} BodyComponent={ } />
)}
); };