Files
web-menu-react-version/src/pages/product/components/Variants.tsx

192 lines
6.4 KiB
TypeScript

import { Divider } from "antd";
import ProRatioGroups from "components/ProRatioGroups/ProRatioGroups";
import ProText from "components/ProText";
import useBreakPoint from "hooks/useBreakPoint";
import { Dispatch, SetStateAction, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { useAppSelector } from "redux/hooks";
import { Variant } from "utils/types/appTypes";
import styles from "../product.module.css";
import { formatPriceUi } from "utils/helpers";
export default function Variants({
selectedVariants,
setSelectedVariants,
variantsList,
}: {
selectedVariants: Record<number, string>;
setSelectedVariants: Dispatch<SetStateAction<Record<number, string>>>;
variantsList: Variant[];
}) {
const { isRTL } = useAppSelector((state) => state.locale);
const { t } = useTranslation();
const { isDesktop } = useBreakPoint();
const { restaurant } = useAppSelector((state) => state.order);
// Determine variant levels based on options array length
const variantLevels = useMemo(() => {
if (!variantsList || variantsList.length === 0) return [];
const maxOptionsLength = Math.max(
...variantsList.map((v) => v.options.length),
);
const levels: Array<{
level: number;
optionKey: string;
optionKeyAR: string;
availableValues: string[];
}> = [];
for (let i = 0; i < maxOptionsLength; i++) {
const optionKey = variantsList[0]?.options[i]?.option || "";
const optionKeyAR = variantsList[0]?.optionsAR?.[i]?.option || "";
if (optionKey) {
const availableValues = [
...new Set(
variantsList
.filter((v) => v.options[i]?.option === optionKey)
.map((v) => v.options[i]?.value)
.filter(Boolean),
),
];
levels.push({
level: i, // Use the actual array index as level number
optionKey,
optionKeyAR,
availableValues,
});
}
}
// console.log("Variant levels:", levels);
// console.log("Selected variants:", selectedVariants);
return levels;
}, [variantsList]);
// Get filtered variants based on current selections
const getFilteredVariants = (level: number) => {
if (!variantsList) return [];
const filtered = variantsList.filter((variant) => {
// Check if all previous level selections match
for (let i = 0; i < level; i++) {
const selectedValue = selectedVariants[i];
if (selectedValue && variant.options[i]?.value !== selectedValue) {
return false;
}
}
return true;
});
// console.log(`Filtered variants for level ${level}:`, {
// level,
// selectedVariants,
// totalVariants: product.variants.length,
// filteredCount: filtered.length,
// filtered: filtered.map((v) => ({ id: v.id, options: v.options })),
// });
return filtered;
};
// Handle variant selection
const handleVariantSelection = (level: number, value: string) => {
setSelectedVariants((prev) => {
const newSelections = { ...prev };
newSelections[level] = value;
// Clear selections for subsequent levels
for (let i = level + 1; i < variantLevels.length; i++) {
delete newSelections[i];
}
// console.log("New selections:", newSelections);
return newSelections;
});
};
return (
<>
{variantsList?.length > 0 && variantLevels.length > 0 && (
<>
{!isDesktop && <Divider style={{ margin: "0 0 10px 0" }} />}
<div>
{variantLevels.map((level, index) => {
const filteredVariants = getFilteredVariants(index);
const availableValues = level.availableValues.filter((value) =>
filteredVariants.some((v) => v.options[index]?.value === value),
);
// Only show this level if there are available values and previous levels are selected
const shouldShowLevel =
index === 0 || selectedVariants[index - 1];
// console.log("Level rendering:", {
// level: level.level,
// index,
// shouldShowLevel,
// availableValues,
// filteredVariants: filteredVariants.length,
// selectedVariants,
// previousLevelSelected:
// selectedVariants[level.level - 1],
// });
if (!shouldShowLevel || availableValues.length === 0) return null;
return (
<div key={level.level} style={{ marginBottom: "16px" }}>
<div
style={{
display: "flex",
justifyContent: "space-between",
}}
>
<ProText strong style={{ fontSize: "1rem" }}>
{isRTL ? level.optionKeyAR : level.optionKey}
</ProText>
<div style={{ display: "flex", alignItems: "center" }}>
<ProText
strong
style={{ fontSize: "0.75rem", color: "red" }}
>
<span style={{ color: "red", fontSize: "0.75rem" }}>
*
</span>
{t("menu.required")}
</ProText>
</div>
</div>
<div className={styles.productContainer}>
<ProRatioGroups
options={availableValues.map((value) => {
const variant = filteredVariants.find(
(v) => v.options[index]?.value === value,
);
return {
value: value,
label: value,
price: variant
? `+${formatPriceUi(variant.price, restaurant.currency_decimals ?? 3)}`
: "",
};
})}
value={selectedVariants[index] || ""}
onRatioClick={(value: string) =>
handleVariantSelection(index, value)
}
/>
</div>
</div>
);
})}
</div>
</>
)}
</>
);
}