Compare commits

..
Author SHA1 Message Date
Unchained 00f63c32f8 fix: use PRODUCT_FRAGMENT to get attributes for bundle detection
Build and Deploy / build (push) Has been cancelled
2026-03-24 20:26:42 +02:00
Unchained 3d8a77dafa refactor: centralize bundle filtering with filterOutBundles helper
Build and Deploy / build (push) Has been cancelled
2026-03-24 20:18:06 +02:00
Unchained bfce7dcca0 fix: filter bundles from homepage, sitemap, and static params
Build and Deploy / build (push) Has been cancelled
2026-03-24 20:14:42 +02:00
Unchained 8f780c3585 fix: bundle UI improvements - remove QTY selector, filter bundles from similar products
Build and Deploy / build (push) Has been cancelled
2026-03-24 18:50:39 +02:00
8 changed files with 28 additions and 37 deletions
+3 -2
View File
@@ -1,4 +1,4 @@
import { getProducts } from "@/lib/saleor";
import { getProducts, filterOutBundles } from "@/lib/saleor";
import { getTranslations, setRequestLocale } from "next-intl/server";
import Header from "@/components/layout/Header";
import Footer from "@/components/layout/Footer";
@@ -40,7 +40,8 @@ export default async function Homepage({ params }: { params: Promise<{ locale: s
console.log("Failed to fetch products during build");
}
const featuredProducts = products?.slice(0, 4) || [];
const filteredProducts = filterOutBundles(products);
const featuredProducts = filteredProducts.slice(0, 4);
const hasProducts = featuredProducts.length > 0;
const basePath = `/${validLocale}`;
+7 -7
View File
@@ -1,4 +1,4 @@
import { getProductBySlug, getProducts, getLocalizedProduct, getBundleProducts } from "@/lib/saleor";
import { getProductBySlug, getProducts, getLocalizedProduct, getBundleProducts, filterOutBundles } from "@/lib/saleor";
import { getTranslations, setRequestLocale } from "next-intl/server";
import Header from "@/components/layout/Header";
import Footer from "@/components/layout/Footer";
@@ -20,7 +20,8 @@ export async function generateStaticParams() {
try {
const saleorLocale = locale === "sr" ? "SR" : "EN";
const products = await getProducts(saleorLocale, 100);
products.forEach((product: Product) => {
const filteredProducts = filterOutBundles(products);
filteredProducts.forEach((product: Product) => {
params.push({ locale, slug: product.slug });
});
} catch (e) {
@@ -88,8 +89,8 @@ export default async function ProductPage({ params }: ProductPageProps) {
let relatedProducts: Product[] = [];
let bundleProducts: Product[] = [];
try {
const allProducts = await getProducts(saleorLocale, 8);
relatedProducts = allProducts
const allProducts = await getProducts(saleorLocale, 50);
relatedProducts = filterOutBundles(allProducts)
.filter((p: Product) => p.id !== product.id)
.slice(0, 4);
} catch (e) {}
@@ -100,10 +101,9 @@ export default async function ProductPage({ params }: ProductPageProps) {
const bundleAttr = p.attributes?.find(
(attr) => attr.attribute.slug === "bundle-items"
);
if (!bundleAttr) return false;
if (!bundleAttr || bundleAttr.values.length === 0) return false;
return bundleAttr.values.some((val) => {
const baseIdPart = product.id.replace("UHJvZHVjdDo", "");
return val.slug.includes(baseIdPart);
return val.name === product.name || p.name.includes(product.name.split(" - ")[0]);
});
});
} catch (e) {}
+4 -2
View File
@@ -1,4 +1,4 @@
import { getProducts } from "@/lib/saleor";
import { getProducts, filterOutBundles } from "@/lib/saleor";
import { getTranslations, setRequestLocale } from "next-intl/server";
import Header from "@/components/layout/Header";
import Footer from "@/components/layout/Footer";
@@ -27,7 +27,9 @@ export default async function ProductsPage({ params }: ProductsPageProps) {
setRequestLocale(validLocale);
const t = await getTranslations("Products");
const saleorLocale = getSaleorLocale(validLocale as Locale);
const products = await getProducts(saleorLocale);
const allProducts = await getProducts(saleorLocale);
const products = filterOutBundles(allProducts);
return (
<>
+4 -2
View File
@@ -1,5 +1,5 @@
import { MetadataRoute } from "next";
import { getProducts } from "@/lib/saleor";
import { getProducts, filterOutBundles } from "@/lib/saleor";
import { SUPPORTED_LOCALES, type Locale } from "@/lib/i18n/locales";
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || "https://dev.manoonoils.com";
@@ -80,9 +80,11 @@ export default async function sitemap(): Promise<SitemapEntry[]> {
},
];
const filteredProducts = filterOutBundles(products);
const productUrls: SitemapEntry[] = [];
for (const product of products) {
for (const product of filteredProducts) {
const hreflangs: Record<string, string> = {};
for (const locale of SUPPORTED_LOCALES) {
const path = locale === "sr" ? `/products/${product.slug}` : `/${locale}/products/${product.slug}`;
-22
View File
@@ -354,28 +354,6 @@ export default function ProductDetail({ product, relatedProducts, bundleProducts
)
)}
<div className="flex items-center gap-4 mb-8">
<span className="text-sm uppercase tracking-[0.1em] font-medium w-16">
{t("qty")}
</span>
<div className="flex items-center border-2 border-[#1a1a1a]">
<button
onClick={() => setQuantity(Math.max(1, quantity - 1))}
className="w-12 h-12 flex items-center justify-center hover:bg-[#f8f9fa] transition-colors"
disabled={quantity <= 1}
>
<Minus className="w-4 h-4" />
</button>
<span className="w-14 text-center text-base font-medium">{quantity}</span>
<button
onClick={() => setQuantity(quantity + 1)}
className="w-12 h-12 flex items-center justify-center hover:bg-[#f8f9fa] transition-colors"
>
<Plus className="w-4 h-4" />
</button>
</div>
</div>
{isAvailable ? (
<button
onClick={handleAddToCart}
+4
View File
@@ -35,4 +35,8 @@ export {
getLocalizedProduct,
parseDescription,
getBundleProducts,
getBundleProductsForProduct,
getProductBundleComponents,
isBundleProduct,
filterOutBundles,
} from "./products";
+4
View File
@@ -217,3 +217,7 @@ export function getProductBundleComponents(product: Product): number | null {
export function isBundleProduct(product: Product): boolean {
return getProductBundleComponents(product) !== null;
}
export function filterOutBundles(products: Product[]): Product[] {
return products.filter((product) => !isBundleProduct(product));
}
+2 -2
View File
@@ -6,7 +6,7 @@ export const GET_PRODUCTS = gql`
products(channel: $channel, first: $first) {
edges {
node {
...ProductListItemFragment
...ProductFragment
}
}
pageInfo {
@@ -15,7 +15,7 @@ export const GET_PRODUCTS = gql`
}
}
}
${PRODUCT_LIST_ITEM_FRAGMENT}
${PRODUCT_FRAGMENT}
`;
export const GET_PRODUCT_BY_SLUG = gql`