import React, { useState, useMemo, useEffect } from "react"; import { useLocation, useNavigate, Link, useParams } from "react-router-dom"; import { SelectedProduct } from "../../services/types"; import { Area, Package } from "../../services/product/type"; import { useMutation, useQuery } from "@tanstack/react-query"; import { DataCacheKey, staleTime } from "../../global/constants"; import { useAppDispatch, useAppSelector } from "../../hooks/useRedux"; import { startLoading, stopLoading } from "../../features/loading/loadingSlice"; import { productApi } from "../../apis/productApi"; import { openPopup } from "../../features/popup/popupSlice"; import { formatCurrency, formatNumber, getWithExpiry, } from "../../logic/loigicUtils"; import ProductInfoModal from "../../components/ProductInfoModal"; import PackageOverview from "./components/PackageOverview"; import ProductCard from "../../components/ProductCard"; import { useTranslation } from "react-i18next"; import { get } from "http"; const ProductDetailView: React.FC = () => { const location = useLocation(); const navigate = useNavigate(); const dispatch = useAppDispatch(); const { t } = useTranslation(); // let area = location.state as Area; const areas = getWithExpiry("areas"); const { id } = useParams<{ id: string }>(); const loading = useAppSelector((state) => state.loading); const [selectedDays, setSelectedDays] = useState(null); const [selectedData, setSelectedData] = useState("Unlimited"); const [daysOptions, setDaysOptions] = useState([]); const [dataOptions, setDataOptions] = useState([]); const [daysActiveOptions, setDaysActiveOptions] = useState([]); const [dataActiveOptions, setDataActiveOptions] = useState([]); const [relatedAreas, setRelatedAreas] = useState([]); const [prices, setPrices] = useState<{ original: string; final: string; discountPercent: string; }>({ original: "0.00", final: "0.00", discountPercent: "0", }); const [simType, setSimType] = useState<"eSIM" | "Physical">("eSIM"); const [quantity, setQuantity] = useState(1); const [packages, setPackages] = useState([]); const [area, setArea] = useState(null); const [selectedPackage, setSelectedPackage] = useState(null); useEffect(() => { console.log("ProductDetailView loaded with id:", id); if (areas && areas.length > 0) { const areaTmp = areas.find((a) => a.id.toString() === id.toString()); setArea(areaTmp); getProductMutation.mutate(); getRelatedAreaMutation.mutate(); console.log("Set area from cache:", areaTmp); } }, [id]); const getProductMutation = useMutation({ mutationFn: async () => { dispatch(startLoading({})); const res = await productApi.loadPackage({ areaId: area?.id, dataType: "-1", }); return res; }, onSuccess: (data) => { dispatch(stopLoading()); console.log("Get package response data:", data); if (data && data.errorCode === "0") { const packages = data.data as Package[]; setPackages(packages); } else { console.error("Get package failed, no token received"); } }, onError: (error: any) => { dispatch(stopLoading()); console.error("Get package error:", error.response.data); }, }); const getRelatedAreaMutation = useMutation({ mutationFn: async () => { dispatch(startLoading({})); const res = await productApi.loadRelatedArea({ areaId: id, }); return res; }, onSuccess: (data) => { dispatch(stopLoading()); console.log("Get package response data:", data); if (data && data.errorCode === "0") { const areas = data.data as Area[]; setRelatedAreas(areas); } else { console.error("Get package failed, no token received"); } }, onError: (error: any) => { dispatch(stopLoading()); console.error("Get package error:", error.response.data); }, }); const convertPackageToSelectedProduct = (packg: Package) => { return packg.title; }; const options = useMemo(() => { console.log("Calculating options from loadPackage"); const daysSet = new Set(); const dataSet = new Set(); packages.forEach((p) => { daysSet.add(p.dayDuration); dataSet.add(convertPackageToSelectedProduct(p)); }); const daysArray = Array.from(daysSet).sort((a, b) => a - b); // const dataArray = Array.from(dataSet).sort((a, b) => { // if (a === "Unlimited") return 1; // if (b === "Unlimited") return -1; // return parseInt(a) - parseInt(b); // }); return { daysArray, dataArray: Array.from(dataSet), }; }, [packages]); useEffect(() => { setDaysOptions(options.daysArray); setDataOptions(options.dataArray); handleSelectDay(options.daysArray[0]); handleSelectData(options.dataArray[0]); // setSelectedPackage(packages.length > 0 ? packages[0] : null); // console.log("Set package successful", packages.length, selectedPackage); }, [options]); useEffect(() => { getPrices(); }, [selectedDays, selectedData]); const handleSelectDay = (day: number) => { // filter data options based on selected day if needed const dataSet = new Set(); packages.forEach((p) => { if (p.dayDuration === day) { dataSet.add(convertPackageToSelectedProduct(p)); } }); setSelectedDays(day); setSelectedData( dataSet.has(selectedData) ? selectedData : Array.from(dataSet)[0], ); setDataActiveOptions(Array.from(dataSet)); setSelectedPackage( packages.find( (p) => p.dayDuration === selectedDays && convertPackageToSelectedProduct(p) === selectedData, ), ); }; const handleSelectData = (data: string) => { // filter day options based on selected data if needed const daysSet = new Set(); packages.forEach((p) => { if (convertPackageToSelectedProduct(p) === data) { daysSet.add(p.dayDuration); } }); setSelectedData(data); setSelectedDays( daysSet.has(selectedDays) ? selectedDays : Array.from(daysSet)[0], ); setDaysActiveOptions(Array.from(daysSet)); setSelectedPackage( packages.find( (p) => p.dayDuration === selectedDays && convertPackageToSelectedProduct(p) === selectedData, ), ); }; const getPrices = (quantityParam?: number) => { const quantityToUse = quantityParam !== undefined ? quantityParam : quantity; // find package based on selectedDays and selectedData let selectedPackageTmp = packages.find( (p) => p.dayDuration === selectedDays && convertPackageToSelectedProduct(p) === selectedData, ); if (!selectedPackageTmp) { // console.log( // "No package found for the selected options " + // selectedDays + // " days and " + // selectedData + // " data" // ); return { original: "0.00", final: "0.00", discountPercent: "0", }; } console.log( "Selected package: ", selectedPackageTmp + " quantity " + quantityToUse, ); setPrices({ original: quantityToUse * selectedPackageTmp.displayPrice, final: quantityToUse * selectedPackageTmp.sellPrice, discountPercent: selectedPackageTmp.discountPercent, }); setSelectedPackage(selectedPackageTmp); }; const handleQuantityChange = (change: number) => { const newQuantity = Math.max(1, quantity + change); setQuantity(newQuantity); console.log("Selected quantity: ", newQuantity); getPrices(newQuantity); }; const handleBuyNow = async () => { // Logic for custom order or standard buy console.log("Buy now clicked"); const selectedPackage = packages.find( (p) => p.dayDuration === selectedDays && convertPackageToSelectedProduct(p) === selectedData, ); if (!selectedPackage) { alert("Please select a valid package"); return; } // call logic to proceed to checkout const res = await productApi.checkout({ packgId: selectedPackage.id, quantity: quantity, }); if (res && res.errorCode === "0") { console.log("Checkout details loaded:", res.data); // navigate to checkout with selected options navigate("/checkout", { state: { area: area, package: selectedPackage, quantity: quantity, simType: simType, checkoutDetails: res.data, }, }); } else { console.error("Failed to load checkout details:", res.message); dispatch( openPopup({ isSuccess: false, title: "Checkout Error", message: res.message || "Failed to proceed to checkout.", buttonText: "Close", }), ); } }; if (!id || !area) { return ( {t("productDetailsMissing")} {t("goToShop")} ); } return ( {t("home")} {area?.areaName1} SIM {area?.areaName1} {t("verified")}:{" "} {t("highSpeed")} {/* Product Information Card */} {t("numberOfDays")} {daysOptions.map((day) => ( // daysActiveOptions.includes(day) && handleSelectDay(day) } className={`min-w-[50px] md:min-w-[70px] h-10 md:h-14 rounded-xl md:rounded-2xl font-bold text-base md:text-xl transition-all border-2 ${ selectedDays === day ? "border-[#EE0434] text-white bg-[#EE0434] shadow-md" : daysActiveOptions.includes(day) ? "border-[#ffffff] text-black bg-[#ffffff] shadow-md" : "border-slate-100 text-slate-300" }`} > {day} ))} Data {dataOptions.map((data) => ( // dataActiveOptions.includes(data) && handleSelectData(data) } className={`h-10 md:h-14 rounded-xl md:rounded-2xl font-bold text-sm md:text-xl transition-all border-2 ${ selectedData === data ? "border-[#EE0434] text-white bg-[#EE0434] shadow-md" : dataActiveOptions.includes(data) ? "border-[#ffffff] text-black bg-[#ffffff] shadow-md" : "border-slate-100 text-slate-300" }`} > {data === "0" ? "Unlimited" : data} ))} {t("simType")} setSimType("eSIM")} className={`flex-1 py-3 md:py-4 rounded-xl font-black text-sm md:text-2xl transition-all ${ simType === "eSIM" ? "bg-[#EE0434] text-white shadow-lg" : "text-slate-300" }`} > eSIM {/* setSimType("Physical")} className={`flex-1 py-3 md:py-4 rounded-xl font-black text-sm md:text-2xl transition-all ${ simType === "Physical" ? "bg-[#EE0434] text-white shadow-lg" : "text-slate-300" }`} > Physical SIM */} {t("quantity")} handleQuantityChange(-1)} className="w-12 h-full bg-white rounded-xl shadow-sm text-slate-600 font-bold text-2xl hover:bg-slate-100 transition-colors" > - {quantity} handleQuantityChange(1)} className="w-12 h-full bg-white rounded-xl shadow-sm text-slate-600 font-bold text-2xl hover:bg-slate-100 transition-colors" > + {prices.discountPercent}% {formatCurrency(prices.original, area?.curency)} {formatCurrency(prices.final, area?.curency)} {loading.isSmallLoading && ( )} {t("buyNow")} {/* Suggestions Section */} {t("suggestionsEsim")} {area.areaName1}: {relatedAreas.map((item) => ( { navigate(`/product-detail/${item.id}`, { state: { ...item, }, }); window.scrollTo({ top: 0, behavior: "smooth" }); }} /> ))} ); }; export default ProductDetailView;
{t("productDetailsMissing")}
{t("verified")}:{" "} {t("highSpeed")}