import React, { useState, useEffect } from "react";
import axios from "axios";
import Cookies from "js-cookie";
import Accordion from "./Accordion";
import { FaMinus, FaPlus } from "react-icons/fa";
import { useAuth } from "@/context/AuthContext";
import { useRouter } from "next/navigation";
import styles from "./Productpricing.module.scss";
function ProductPricing({ productData }) {
const [selectedAttributes, setSelectedAttributes] = useState({});
const [matchingPrices, setMatchingPrices] = useState([]);
const [matchingSkuIds, setMatchingSkuIds] = useState([]);
const [matchingName, setMatchingName] = useState([]);
const [noMatchingSku, setNoMatchingSku] = useState(false);
const storedMobileNumber = Cookies.get("mobileNumber");
const [amount, setAmount] = useState(1);
const { user } = useAuth();
const navigate = useRouter();
const [lastValidSkuName, setLastValidSkuName] = useState("");
const setDecrease = () => {
amount > 1 ? setAmount(amount - 1) : setAmount(1);
};
const setIncrease = () => {
setAmount(amount + 1);
};
const handleInputChange = (e) => {
// Ensure the input value is a positive integer
const newValue = parseInt(e.target.value, 10);
if (!isNaN(newValue) && newValue >= 1) {
setAmount(newValue);
}
};
useEffect(() => {
if (
productData.responseProductSkus &&
productData.responseProductSkus.length > 0
) {
// Set the default selected attributes based on the first SKU
const firstSku = productData.responseProductSkus[0];
const defaultAttributes = {};
firstSku.responseSkuParams.forEach((param) => {
defaultAttributes[param.key] = param.value;
});
setSelectedAttributes(defaultAttributes);
}
}, [productData]);
useEffect(() => {
calculateMatchingPrices();
}, [productData.responseProductSkus, selectedAttributes]);
useEffect(() => {
if (!noMatchingSku) {
const urlFriendlyProductName = getMatchingSkuName();
if (urlFriendlyProductName) {
setLastValidSkuName(urlFriendlyProductName); // Update last valid SKU name
const url = `/product/${urlFriendlyProductName}/${productData.externalProductId}`;
navigate.replace(url);
} else if (lastValidSkuName) {
const url = `/product/${lastValidSkuName}/${productData.externalProductId}`;
navigate.replace(url);
}
}
}, [selectedAttributes, noMatchingSku, navigate]);
const calculateMatchingPrices = () => {
const matchingProducts = productData.responseProductSkus.filter((sku) => {
const skuParams = {};
sku.responseSkuParams.forEach((param) => {
skuParams[param.key] = param.value;
});
return Object.entries(selectedAttributes).every(
([key, value]) =>
value === "" || value === undefined || skuParams[key] === value
);
});
if (matchingProducts.length === 0) {
setNoMatchingSku(true);
} else {
setNoMatchingSku(false);
}
const prices = matchingProducts.flatMap((sku) => [
sku.prices.find((price) => price.pricingType === "UNIT")?.price,
sku.prices.find((price) => price.pricingType === "FINAL")?.price,
]);
const skuIds = matchingProducts.map((sku) => sku.externalProductSkuId);
const names = matchingProducts.map((sku) => sku.name);
setMatchingPrices(prices);
setMatchingSkuIds(skuIds);
setMatchingName(names);
};
const getMatchingSkuName = () => {
// Implement this function to find the SKU name based on selected attributes
// This is just a placeholder implementation
const matchingSku = productData.responseProductSkus.find((sku) => {
const skuParams = {};
sku.responseSkuParams.forEach((param) => {
skuParams[param.key] = param.value;
});
return Object.entries(selectedAttributes).every(
([key, value]) =>
value === "" || value === undefined || skuParams[key] === value
);
});
if (!matchingSku) return lastValidSkuName;
return matchingSku.name
.trim() // Remove leading/trailing spaces
.replace(/s+/g, "-") // Replace spaces with hyphens
.replace(/--+/g, "-") // Replace multiple hyphens with a single hyphen
.replace(/[^a-zA-Z0-9.-*]/g, "") // Remove all special characters except periods, hyphens, and alphanumeric characters
.replace(/([*])/g, "$1"); // Preserve periods
};
const handleAttributeChange = (key, value) => {
setSelectedAttributes((prevSelected) => ({
...prevSelected,
[key]: value,
}));
};
const renderAttributeLists = () => {
const uniqueAttributes = {};
productData.responseProductSkus &&
productData.responseProductSkus.forEach((sku) => {
sku.responseSkuParams.forEach((param) => {
if (!uniqueAttributes[param.key]) {
uniqueAttributes[param.key] = [];
}
if (!uniqueAttributes[param.key].includes(param.value)) {
uniqueAttributes[param.key].push(param.value);
}
});
});
return Object.entries(uniqueAttributes).map(([key, values]) => (
<div key={key} className={styles.attribute_list}>
<h3>{key}:</h3>
<ul className={styles.attribute_row}>
{values.map((value) => (
<li
key={value}
className={`${styles.attribute_item} ${
selectedAttributes[key] === value ? styles.selected : ""
}`}
onClick={() => handleAttributeChange(key, value)}
>
{value}
</li>
))}
</ul>
</div>
));
};
let minPrice = Infinity;
let minPriceSku = null;
let minPriceTex = null;
let minPriceTex1 = null;
// SKU iteration and minimum price calculation
if (productData?.responseProductSkus) {
for (const sku of productData.responseProductSkus) {
for (const price of sku.prices) {
if (price.pricingType === "UNIT" && price.price < minPrice) {
minPrice = price.price;
minPriceSku = sku;
}
}
}
if (minPriceSku) {
const unitPrice = minPriceSku.prices.find(
(price) => price.pricingType === "UNIT"
);
const finalPrice = minPriceSku.prices.find(
(price) => price.pricingType === "FINAL"
);
if (unitPrice && finalPrice) {
minPriceTex = unitPrice.priceText;
minPriceTex1 = finalPrice.priceText;
}
}
}
const addtocart = async () => {
try {
const authToken = localStorage.getItem("authToken");
const headers = {
accept: "*/*",
authToken: authToken,
};
// eslint-disable-next-line no-unused-vars
const response = await axios.post(
`${process.env.NEXT_PUBLIC_API_URL}/cart/add`,
{
authToken: "NULL",
customerMobile: storedMobileNumber,
skuExternalId: matchingSkuIds[0],
quantity: amount,
},
{ headers: headers }
);
window.location.href = "/cart"; // Handle the response as needed
} catch (error) {
console.error(error);
}
};
return (
<div className={styles.product_data}>
{noMatchingSku && (
<p className={styles.notavbl}>This variant isn't available</p>
)}
<h2>{matchingName}</h2>
{user && user.authToken ? (
<>
<strong className={styles.price_heading}>Rate Inclusive GST</strong>
<div className={styles.price}>
<div className={styles.price_data}>
<p>Per {minPriceTex}</p>
<p className={styles.product_data_price}>₹ {matchingPrices[0]}</p>
</div>
<div className={styles.price_data}>
<p>Per {minPriceTex1}</p>
<p className={styles.product_data_price}>₹ {matchingPrices[1]}</p>
</div>
</div>
</>
) : (
<p>To See Prices Please Sign Up.</p>
)}
{renderAttributeLists()}
<div>
<h3 className={styles.qty}>Quantity:</h3>
<div className={styles.cart_button}>
<div className={styles.amount_toggle}>
<button onClick={() => setDecrease()}>
<FaMinus />
</button>
<div className={styles.amount_style}>
<input
type="text"
name="amount"
value={amount}
onChange={handleInputChange}
/>
</div>
<button onClick={() => setIncrease()}>
<FaPlus />
</button>
</div>
</div>
</div>
<div>
<div className={styles.accordion}>
<Accordion
title="Product Details"
productInfo={productData.productInfo}
description={productData.description}
/>
</div>
</div>
<button className={styles.btn} onClick={addtocart}>
Add to Cart
</button>
</div>
);
}
export default ProductPricing;
I tried changing the dependencies of useEffects and also console logging to check if the skus change or not,but everything worked fine .This same component worked fine in react.js,but in next.js it first renders the new sku but then changes back to the default sku.
I cannot figure out where i am going wrong or what is the issue if it is regarding to state or useeffects,or something that is different in nextjs than react