Android_Retail/src/Pages/Reports/MenuQRCode/CustomerMenuPage.jsx

478 lines
16 KiB
JavaScript

import { useEffect, useRef, useState } from "react";
import axios from "axios";
import { Phone, Mail, Globe, MapPin, Facebook, Instagram } from "lucide-react";
import "./MenuQRCode.scss";
import { decryptToObject, sessionStore } from "../../../Services/Others";
import { useDispatch } from "react-redux";
import {
PublicQrCodeget,
} from "../../../Features/ConfigMasterPage/ConfigMasterPage";
import {
Comboget,
getCardDataWithoutSubmodule,
getLayoutCategories,
getLayoutSubCategories,
getLayoutproductCard,
} from "../../../Features/BookingScreen/BookingData/BookingData";
import { getBranchDetail } from "../../../Features/BrachLogin/BranchLogin";
const url_string = window.location.href;
const url = new URL(url_string);
const codesParam = url.searchParams.get("code");
const CustomerMenuPage = () => {
const apiUrlToken = import.meta.env.ENV_API_URL_TOKEN;
const dispatch = useDispatch();
const categoriesRef = useRef(null);
const [activeCategory, setActiveCategory] = useState(null);
const [activeCategoryType, setActiveCategoryType] = useState(null); // 'combo' or 'regular'
const [decryptedData, setDecryptedData] = useState(null);
const [categories, setCategories] = useState([]);
const [selectedCategoryObj, setSelectedCategoryObj] = useState(null);
const [subCategories, setSubCategories] = useState([]);
const [noSubcatCardData, setNoSubcatCardData] = useState([]);
const [activeProdSubCat, setActiveProdSubCat] = useState(null);
const [brachData, setBrachData] = useState(null);
const [comboData, setComboData] = useState([]);
const [comboItems, setComboItems] = useState([]);
const [selectedComboId, setSelectedComboId] = useState(null);
// Initialize data on mount
useEffect(() => {
initializeData();
}, []);
// Fetch combo data after decrypted data is available
useEffect(() => {
if (decryptedData) {
CombogetData();
}
}, [decryptedData]);
// Fetch products when category/subcategory changes
useEffect(() => {
if (activeCategoryType === 'regular' && selectedCategoryObj) {
fetchProducts();
} else if (activeCategoryType === 'combo' && selectedComboId) {
fetchComboItems(selectedComboId);
}
}, [selectedCategoryObj, activeProdSubCat, selectedComboId, activeCategoryType]);
const initializeData = async () => {
try {
await addSession();
await getQrCode();
} catch (error) {
console.error("Initialization error:", error);
}
};
const getQrCode = async () => {
try {
const qrData = await dispatch(PublicQrCodeget(codesParam)).unwrap();
const oldUrl = qrData?.data?.data?.[0]?.OldUrl;
const decrypted = decryptToObject(oldUrl);
if (!decrypted) {
console.error("Invalid decrypted data");
return;
}
const { BranchId, CompId, AppId, UserId } = decrypted;
if (BranchId && CompId && AppId) {
setDecryptedData({ BranchId, CompId, AppId, UserId });
await getBranchDetailData(BranchId);
await fetchCategories({ BranchId, CompId, AppId, UserId });
}
} catch (error) {
console.error("Error fetching QR code:", error);
}
};
const getBranchDetailData = async (BranchId) => {
const response = await dispatch(getBranchDetail({ BrId: BranchId })).unwrap();
setBrachData(response?.data?.data?.[0]);
};
const addSession = async () => {
if (!sessionStorage.getItem("auth")) {
try {
const { data } = await axios.post(`${apiUrlToken}/jwtTokenGenerator`, {
username: "1000000001",
password: "1234",
});
sessionStorage.setItem("auth", data.token);
sessionStore("LoginType");
} catch (error) {
console.error("Session Error:", error);
}
}
};
const CombogetData = async () => {
try {
const data = {
BranchId: decryptedData.BranchId,
CompId: decryptedData.CompId,
AppId: decryptedData.AppId,
ActiveStatus: "A"
};
const response = await dispatch(Comboget(data)).unwrap();
const combos = response?.data?.data || [];
setComboData(combos);
// Don't auto-select combo anymore - let user click on "Combo Offer"
} catch (error) {
console.error("Error fetching Combo data:", error);
}
};
const fetchComboItems = (comboId) => {
try {
// Find the selected combo and display its items
const selectedCombo = comboData.find(c => c.ComboId === comboId);
if (selectedCombo && selectedCombo.ComboInwardDetails && selectedCombo.ComboInwardDetails.length > 0) {
// Extract ComboDetails from the first ComboInwardDetails
const comboDetails = selectedCombo.ComboInwardDetails[0].ComboDetails || [];
setComboItems(comboDetails);
} else {
setComboItems([]);
}
} catch (error) {
console.error("Error fetching combo items:", error);
setComboItems([]);
}
};
const fetchCategories = async ({ BranchId, CompId, AppId, UserId }) => {
try {
const response = await dispatch(
getLayoutCategories({ BranchId, CompId, AppId, UserId })
).unwrap();
const categoryData = response?.data?.data || [];
setCategories(categoryData);
// Set first regular category as active by default
if (categoryData.length > 0) {
const firstCategory = categoryData[0];
setActiveCategory(firstCategory.ProdCat);
setActiveCategoryType('regular');
setSelectedCategoryObj(firstCategory);
await fetchSubCategories(firstCategory);
}
} catch (error) {
console.error("Error fetching categories:", error);
}
};
const fetchSubCategories = async (category) => {
try {
const response = await dispatch(
getLayoutSubCategories({
BranchId: category.BranchId,
CompId: category.CompId,
AppId: category.AppId,
ProdCat: category.ProdCat,
})
).unwrap();
const subCatData = response?.data?.data || [];
setSubCategories(subCatData);
if (subCatData.length > 0) {
setActiveProdSubCat(subCatData[0].ProdSubCat);
} else {
setActiveProdSubCat(null);
}
} catch (error) {
console.error("Error fetching subcategories:", error);
setSubCategories([]);
setActiveProdSubCat(null);
}
};
const fetchProducts = async () => {
if (!selectedCategoryObj) return;
try {
const { CompId, BranchId, AppId, ProdCat } = selectedCategoryObj;
if (activeProdSubCat !== null) {
const response = await dispatch(
getLayoutproductCard({
CompId,
BranchId,
AppId,
ProdSubCat: activeProdSubCat,
})
).unwrap();
if (response?.data?.statusCode === 1) {
setNoSubcatCardData(response?.data?.data || []);
}
} else {
const response = await dispatch(
getCardDataWithoutSubmodule({
compId: CompId,
branchId: BranchId,
appId: AppId,
prodCat: ProdCat,
})
).unwrap();
if (response?.data?.statusCode === 1) {
setNoSubcatCardData(response?.data?.data || []);
}
}
} catch (error) {
console.error("Error fetching products:", error);
setNoSubcatCardData([]);
}
};
const handleComboClick = () => {
setActiveCategory('combo-offer');
setActiveCategoryType('combo');
setSelectedCategoryObj(null);
setSubCategories([]);
setActiveProdSubCat(null);
setSelectedComboId(null);
setComboItems([]);
};
const handleComboSubCategoryClick = (comboId) => {
setSelectedComboId(comboId);
};
const handleCategoryClick = async (cat) => {
setActiveCategory(cat.ProdCat);
setActiveCategoryType('regular');
setSelectedCategoryObj(cat);
await fetchSubCategories(cat);
};
const handleSubCategoryClick = (subCat) => {
setActiveProdSubCat(subCat.ProdSubCat);
};
const scrollCategories = (distance) => {
categoriesRef.current.scrollBy({
left: distance,
behavior: "smooth",
});
};
const displayItems = activeCategoryType === 'combo' ? comboItems : noSubcatCardData;
console.log(displayItems, "displayItems")
// Get combo details for display
const selectedCombo = activeCategoryType === 'combo' && selectedComboId
? comboData.find(c => c.ComboId === selectedComboId)
: null;
const displayTitle = activeCategoryType === 'combo'
? (selectedCombo?.ComboName || "Combo Offers")
: selectedCategoryObj?.ProdCatName || "Menu";
// Calculate total combo price
const comboTotalPrice = selectedCombo?.ComboInwardDetails?.[0]?.TotalSellPrice || 0;
const comboOfferPrice = selectedCombo?.ComboInwardDetails?.[0]?.OfferPrice || 0;
const comboDiscountedPrice = comboOfferPrice
? comboTotalPrice - (comboTotalPrice * comboOfferPrice / 100)
: comboTotalPrice;
return (
<div className="menuq-container">
<header className="menuq-header">
<div>
<img src={brachData?.CompLogo} alt="logo" />
</div>
<div style={{ textAlign: 'left' }}>
<h1 className="menuq-header-title">{brachData?.BrName}</h1>
<p className="menuq-header-address">
{brachData?.Address1} {brachData?.Address2} {brachData?.City} {brachData?.Dist} {brachData?.State} {brachData?.Zip}
</p>
<p className="menuq-header-contact">
{brachData?.BrMobile}, {brachData?.BrMobile2}
</p>
</div>
</header>
<div className="menuq-categories-wrapper">
<button className="scroll-btn left" onClick={() => scrollCategories(-100)}>
&#8592;
</button>
<nav className="menuq-categories" ref={categoriesRef}>
{/* Show Static "Combo Offer" Button First (only if combos exist) */}
{comboData.length > 0 && (
<button
onClick={handleComboClick}
className={`menuq-category ${activeCategory === 'combo-offer' && activeCategoryType === 'combo'
? "menuq-category--active"
: ""
}`}
>
Combo Offers
</button>
)}
{/* Then Show Regular Categories */}
{categories.map((cat) => (
<button
key={`cat-${cat.ProdCat}`}
onClick={() => handleCategoryClick(cat)}
className={`menuq-category ${activeCategory === cat.ProdCat && activeCategoryType === 'regular'
? "menuq-category--active"
: ""
}`}
>
{cat.ProdCatName}
</button>
))}
</nav>
<button className="scroll-btn right" onClick={() => scrollCategories(100)}>
&#8594;
</button>
</div>
<section className="menuq-content">
<div className="menuq-card">
{/* <h2 className="menuq-card-title">{displayTitle}</h2> */}
{/* Show subcategory filters only for regular categories */}
{activeCategoryType === 'regular' && (
<div className="menuq-filters">
{subCategories.length > 0 ? (
subCategories.map((subCat) => {
const displayName = subCat.ProdSubCatName?.trim() || "General";
return (
<button
key={subCat.ProdSubCat || "general"}
onClick={() => handleSubCategoryClick(subCat)}
className={`menuq-filter ${activeProdSubCat === subCat.ProdSubCat
? "menuq-filter--active"
: ""
}`}
>
{displayName}
</button>
);
})
) : (
<button
className="menuq-filter menuq-filter--active"
onClick={() => setActiveProdSubCat(null)}
>
General
</button>
)}
</div>
)}
<div className="menuq-items">
{activeCategoryType === 'combo' && activeCategory === 'combo-offer' ? (
comboData.map((combo, i) => {
const comboDetail = combo.ComboInwardDetails?.[0];
const totalPrice = comboDetail?.TotalSellPrice || 0;
const offerPrice = comboDetail?.OfferPrice || 0;
const discountedPrice = offerPrice
? totalPrice - (totalPrice * offerPrice / 100)
: totalPrice;
const comboImage = combo.ComboImage;
return (
<div key={i} className="menuq-item">
<div className="menuq-image-item-price">
{comboImage && (
<img
src={comboImage}
alt={combo.ComboName}
className="menuq-item-image"
/>
)}
</div>
<div className="menuq-item-info">
<h3 className="menuq-item-name">{combo.ComboName}</h3>
<p className="menuq-item-cuisine">{combo.ComboDescription || 'Combo Offer'}</p>
<div className="menuq-item-price">
{offerPrice > 0 && (
<span style={{ textDecoration: 'line-through', color: '#999', marginRight: '8px' }}>
{totalPrice.toFixed(2)}
</span>
)}
{discountedPrice.toFixed(2)}/-
{offerPrice > 0 && (
<span style={{ color: '#28a745', marginLeft: '8px', fontSize: '0.9em' }}>
({offerPrice}% OFF)
</span>
)}
</div>
</div>
</div>
);
})
) : displayItems.length > 0 ? (
displayItems.map((item, i) => {
// For combo items, get price from StockDetails
const stockDetail = item.StockDetails?.[0];
const itemPrice = activeCategoryType === 'combo'
? (stockDetail?.SellPrice || stockDetail?.MRP || 0)
: (item.ProductDetail?.[0]?.ProdVariantDetails?.[0]?.StockDetails?.[0]?.SellPrice || 0);
// For combo items, use ComboQty or ProductQty
const quantity = activeCategoryType === 'combo'
? (item.ComboQty || item.ProductQty || 1)
: 1;
const stockAvailable = (item.ProductDetail?.[0]?.StockAvailable === 'Y' && item.ProductDetail?.[0]?.ProdVariantDetails?.[0]?.OverAllQty === 0);
return (
<div key={i} className="menuq-item">
<div className="menuq-image-item-price">
{(item.ProductDetail?.[0]?.ProdLogo || item.ProdLogo) && (
<img
src={item.ProductDetail?.[0]?.ProdLogo || item.ProdLogo}
alt={item.ProdName}
className="menuq-item-image"
/>
)}
</div>
<div className="menuq-item-info">
<h3 className="menuq-item-name">
{item.ProdName}
{activeCategoryType === 'combo' && quantity > 1 && (
<span style={{ fontSize: '0.9em', color: '#666', marginLeft: '8px' }}>
(Qty: {quantity})
</span>
)}
</h3>
<p className="menuq-item-cuisine">
{item.ProdSubCatName || item.ProdCatName ||
(activeCategoryType === 'combo' ? `${item.UomName || 'Item'} - Size: ${item.Size || 'N/A'}` : '')}
</p>
<div className={`menuq-item-price ${stockAvailable ? 'not-available' : ''}`}>
{stockAvailable ? 'Not Available' : `${itemPrice.toFixed(2)}/-`}
</div>
</div>
</div>
);
})
) : (
<p>No products available.</p>
)}
</div>
</div>
</section>
</div>
);
};
export default CustomerMenuPage;