diff --git a/VERSIONING.md b/VERSIONING.md index 6f536e1..006023a 100644 --- a/VERSIONING.md +++ b/VERSIONING.md @@ -214,3 +214,4 @@ Potential future additions to version system: ## Questions? For questions about the versioning system, see the About page or contact via the FAQ section. +| STS-3.0.1 | 2026-07-01 | Variant groups count & list as one item across all pages (shared lib/variants.ts helper) | diff --git a/app/collections/CollectionCard.tsx b/app/collections/CollectionCard.tsx index cecf381..777b8ef 100644 --- a/app/collections/CollectionCard.tsx +++ b/app/collections/CollectionCard.tsx @@ -3,6 +3,7 @@ import Link from 'next/link'; import { useEffect, useState, useMemo } from 'react'; import FadeImage from '@/components/FadeImage'; +import { countDistinctProducts } from '@/lib/variants'; interface CollectionCardProps { collection: { @@ -92,8 +93,8 @@ export default function CollectionCard({ collection, design, tick }: CollectionC fontFamily: design.fonts.bodyFont, }} > - {collection.products.length}{' '} - {collection.products.length === 1 ? 'product' : 'products'} + {countDistinctProducts(collection.products)}{' '} + {countDistinctProducts(collection.products) === 1 ? 'product' : 'products'}

{ - if (!product.variants || product.variants.length === 0) return true; - return product.variants[0].id === product.id; - }); + // One card per variant group (shared helper — see lib/variants.ts) + const displayProducts = dedupeVariantGroups(sortedProducts); return (
diff --git a/app/page.tsx b/app/page.tsx index 97de2d8..71226ca 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -3,6 +3,8 @@ import Link from 'next/link'; import { useEffect, useState } from 'react'; import FadeImage from '@/components/FadeImage'; +import VariantChips from '@/components/VariantChips'; +import { countDistinctProducts, dedupeVariantGroups, variantDisplayName } from '@/lib/variants'; export default function Home() { const [design, setDesign] = useState(null); @@ -33,7 +35,7 @@ export default function Home() { products.push(product); }); }); - setAllProducts(products); + setAllProducts(dedupeVariantGroups(products)); try { const inventoryResponse = await fetch('/api/inventory'); @@ -215,7 +217,7 @@ export default function Home() {
@@ -231,8 +233,9 @@ export default function Home() { className="font-bold text-lg mb-1" style={{ color: design.colors.primary, fontFamily: design.fonts.titleFont }} > - {product.name} + {variantDisplayName(product)} +

SKU: {product.sku}

@@ -299,8 +302,8 @@ export default function Home() { fontFamily: design.fonts.bodyFont, }} > - {collection.products.length}{' '} - {collection.products.length === 1 ? 'product' : 'products'} + {countDistinctProducts(collection.products)}{' '} + {countDistinctProducts(collection.products) === 1 ? 'product' : 'products'}

@@ -181,8 +183,9 @@ export default function ShopAllPage() { fontFamily: design.fonts.titleFont, }} > - {product.name} + {variantDisplayName(product)} +

; +}): ReactElement | null { + if (!product.variants || product.variants.length === 0) return null; + const seen = new Set(); + const uniqueValues = product.variants + .map((v) => v.values[0]) + .filter((val) => val && !seen.has(val) && !!seen.add(val)); + + return ( +

+

+ {product.variantDimensions?.[0] ?? 'Options'}: +

+
+ {uniqueValues.map((value) => { + const withValue = product.variants!.filter((v) => v.values[0] === value); + const allOOS = withValue.length > 0 && withValue.every( + (v) => stockMap[v.id] !== undefined && stockMap[v.id] <= 0 + ); + const isActive = product.variantValues?.[0] === value; + return ( + + {value} + + ); + })} +
+
+ ); +} diff --git a/lib/variants.ts b/lib/variants.ts new file mode 100644 index 0000000..28cd5d3 --- /dev/null +++ b/lib/variants.ts @@ -0,0 +1,31 @@ +// lib/variants.ts — Variant grouping helpers (STS-3.0.0+) +// +// A "variant group" is 2+ sibling products that share a base name (e.g. the same +// product in several sizes or colors). The catalog engine stamps a `variants` +// array onto every member of a group. These helpers collapse a group down to a +// single representative product so that product LISTINGS and product COUNTS treat +// one variant set as one item (instead of one per size/color). + +export interface VariantLike { + id: string; + variants?: { id: string }[]; +} + +// Returns one representative per variant group (the first variant in the group), +// leaving non-variant products untouched. Input order is preserved. +export function dedupeVariantGroups(products: T[]): T[] { + return products.filter( + (p) => !p.variants || p.variants.length === 0 || p.variants[0].id === p.id + ); +} + +// Count of distinct products, treating each variant group as a single item. +export function countDistinctProducts(products: VariantLike[]): number { + return dedupeVariantGroups(products).length; +} + +// Display name for a card: the variant group base name (e.g. "Branded Sneakers") +// rather than the folder name of one variant ("Branded Sneakers (10)"). +export function variantDisplayName(product: { name: string; variantGroup?: string }): string { + return product.variantGroup || product.name; +} diff --git a/lib/version.ts b/lib/version.ts index 5e70c77..3cfb870 100644 --- a/lib/version.ts +++ b/lib/version.ts @@ -36,7 +36,7 @@ * 4. Commit with version number in commit message */ -export const VERSION = 'STS-2.6.3'; +export const VERSION = 'STS-3.0.1'; export const VERSION_INFO = { name: 'Shop Template System', diff --git a/package.json b/package.json index c370421..e160e27 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "shop-template-system", - "version": "3.0.0", + "version": "3.0.1", "private": true, "scripts": { "dev": "next dev",