CROP

Category Page Update Summary

Summary of the category page redesign and brands SEO improvements shipped in the category-page-update feature branch.

Feature Branch: feature/category-page-update — Summary

Branch: https://github.com/CT-CROP/CROP-front/tree/feature/category-page-update Commits:

  • 3a2cbf11 — feat: category page update and brands SEO
  • d18d6922 — refactor: update styling for cart summary and safety banners

Analysis date: 2026-02-22 Diff: 407 files, +11 275 / -9 776 lines


1. Main Change: /catalog -> /parts

The entire app/catalog/ directory has been renamed to app/parts/. All links, imports, and routes have been updated.

Redirects (301, middleware.ts)

Old URLNew URLType
/catalog/parts301
/catalog/[id]/parts/[id]301
/hydraulics (root-level category)/parts/hydraulics301
?manufacturer=xxx?brand=xxx301
?brand=VNT (vendor code)?brand=ventrac (slug)301

2. New URL Structure

2.1 Parts (parts catalog)

/parts                                    — All parts (catalog main page)
/parts/[slug]                             — Category OR specific part (SKU)
/parts/[slug]/[subcategory]               — Subcategory
/parts/[slug]/[subcategory]/[brand]       — Subcategory + brand

How /parts/[slug] distinguishes category from SKU:

  1. Checks CATEGORY_SLUG_SET.has(slug) (O(1) lookup)
  2. If slug is in the category set (hydraulics, electrical, ...) — renders category page
  3. Otherwise — tries to find a part by slug/SKU
  4. If neither found — 404

2.2 Brands (SEO pages) — NEW

/brands                                   — Grid of all brands
/brands/[brand]                           — All parts for a brand
/brands/[brand]/[category]                — Brand + category
/brands/[brand]/[category]/[subcategory]  — Brand + category + subcategory

2.3 Inventory (equipment)

/inventory                                — Used equipment catalog
/inventory/[category]                     — Equipment category OR equipment detail

/inventory/[category] — dual-purpose: if slug matches a known category (tractors, mowers, ...) — category page. Otherwise — tries to load as equipment detail.


3. Taxonomy: Categories, Subcategories, Brands

3.1 Parts Categories

Defined in lib/catalog-taxonomy.ts

NameSlugAPI categoryNameSort
HydraulicshydraulicsHYDRAULICS1
ElectricalelectricalELECTRICAL2
EngineengineENGINE3
FiltersfiltersFILTERS4
DrivetraindrivetrainDRIVETRAIN5

3.2 Subcategories

CategorySubcategories (slug)categoryPath (API)
Hydraulicspumps, valves, cylinders, hoses, fittings, motors, filters, accumulatorsHYDRAULICS > PUMPS, ...
Electricalbatteries, switchesELECTRICAL > BATTERIES, ...
Enginefilters, beltsENGINE > FILTERS, ...
Filtersair-filters, oil-filtersFILTERS > AIR FILTERS, ...
DrivetraintransmissionsDRIVETRAIN > TRANSMISSIONS

3.3 Brands

NameSlugVendor CodeSort
New Hollandnew-hollandNHL1
McHalemchaleMCH2
VentracventracVNT3
Club Carclub-carCLC4
Briggs & Strattonbriggs-strattonBNS5

3.4 Equipment Categories (Inventory)

Defined in lib/inventory-categories.ts

SlugName
tractorsTractors
mowersMowers
loadersLoaders
skid-steersSkid Steers
combinesCombines
hayHay
tillageTillage
sprayersSprayers
plantersPlanters
attachmentsAttachments

4. Query Parameters

4.1 Parts Catalog (/parts/*)

Defined in lib/catalog/catalog-search-params.ts (nuqs)

URL paramDescriptionDefault
qSearch query (formerly search)""
brandBrand slug (formerly manufacturer)""
categoryIdCategory slug""
categoryPathPath CATEGORY > SUBCATEGORY for API""
pagePage number1
sortByrelevance / price_asc / price_desc"relevance"
priceBucketpriced / contact""
priceMin / priceMaxPrice range
inStockIn stockfalse
hasImageHas imagefalse
has360Has 360 photofalse
modeauto / parts / equipment"parts"
availabilityin_stock / out_of_stock""
statusactive / discontinued / superseded""
equipmentFitmentEquipment fitment""
equipmentModelKeyEquipment model""

Important: manufacturer -> brand and search -> q — URL-level renames (nuqs urlKeys).

4.2 Inventory (/inventory/*)

Defined in lib/catalog/inventory-search-params.ts

URL paramDescriptionDefault
categoryEquipment category slug""
brandManufacturer slug (formerly manufacturer)""
yearYear""
conditionCondition""
searchSearch""
sortByprice_asc / price_desc / year_desc
hasPricePrice available onlyfalse
hasImageImage filter"all"
pagePage1

5. Middleware (middleware.ts)

Processing order:

  1. Redirect ?manufacturer= -> ?brand= (301)
  2. Redirect ?brand=vendorCode -> ?brand=slug (301, e.g. vnt -> ventrac)
  3. Redirect /catalog -> /parts (301)
  4. Redirect /catalog/[id] -> /parts/[id] (301)
  5. Redirect /[categorySlug] -> /parts/[categorySlug] (301, for root-level categories)
  6. Redirect non-www -> www (308, for clintontractor.net)
  7. Auth enforcement for protected routes (/account, /admin, /rnd)
  8. ISR cache for /parts/*, /inventory/*, /brands/*

Caching:

Cache-Control: public, s-maxage=60, stale-while-revalidate=300
  • /parts/*, /inventory/*, /brands/* — cached (60s TTL)
  • /cart/*, /checkout/*, /account/* — NOT cached

6. Navigation: Multiple Paths to the Same Content

The same set of parts can be found via different paths:

Category-first:       /parts/hydraulics
With brand filter:    /parts/hydraulics?brand=new-holland
Subcategory:          /parts/hydraulics/pumps
Subcategory+brand:    /parts/hydraulics/pumps/new-holland

Brand-first:          /brands/new-holland
Brand+category:       /brands/new-holland/hydraulics
Brand+subcategory:    /brands/new-holland/hydraulics/pumps

7. Data Fetching

fetchCatalogByTaxonomy()lib/catalog/fetch-catalog-by-taxonomy.ts

Unified function for loading data on all category/brand pages.

Input:

{
  category?: string;       // "HYDRAULICS" (API categoryName)
  categoryPath?: string;   // "HYDRAULICS > PUMPS" (exact path for API)
  categorySlug?: string;   // "hydraulics" (for initialFilters)
  manufacturer?: string;   // "new-holland" (slug, resolved to vendorCode)
}

Output:

{
  parts: UnifiedCatalogPart[];
  total: number;
  currentPage: number;
  totalPages: number;
  hasNextPage: boolean;
  manufacturers: ManufacturerFacetSummary[];
  facets: SearchFacets | null;
  equipmentFacet: EquipmentFacet | null;
  initialFilters: CatalogFilters;
}

Pagination: 20 items per page


8. Breadcrumbs

PageBreadcrumbs
/partsHome > Parts
/parts/hydraulicsHome > Parts > Hydraulics
/parts/hydraulics/pumpsHome > Parts > Hydraulics > Pumps
/parts/hydraulics/pumps/new-hollandHome > Parts > Hydraulics > Pumps > New Holland
/brands/new-hollandHome > Parts > Brands > New Holland
/brands/new-holland/hydraulicsHome > Parts > Brands > New Holland > Hydraulics
/brands/new-holland/hydraulics/pumpsHome > Parts > Brands > New Holland > Hydraulics > Pumps
/inventory/tractorsHome > Inventory > Tractors

9. New Components

ComponentFilePurpose
CategoryHybridHerocomponents/catalog/category-hybrid-hero.tsxUniversal hero block for categories/brands/subcategories. Supports breadcrumbs, watermark image, background, subcategory carousel
SubcategoryNavcomponents/catalog/subcategory-nav.tsxSubcategory carousel (3 cols mobile, 4 tablet, 6 desktop)
TaxonomyBreadcrumbscomponents/catalog/taxonomy-breadcrumbs.tsxBreadcrumb rendering (shadcn Breadcrumb)
CatalogBottomCtacomponents/catalog/catalog-bottom-cta.tsxCTA block below catalog results
SurfaceCardcomponents/ui/surface-card.tsxUniversal card component

SVG illustrations for equipment categories:

public/images/category/combines.svg
public/images/category/loaders.svg
public/images/category/mowers.svg
public/images/category/skid-steers.svg
public/images/category/tractors.svg

10. File Structure (new/moved files)

app/
├── parts/                    # RENAMED from catalog/
│   ├── page.tsx              # /parts — catalog main page
│   ├── loading.tsx
│   ├── error.tsx
│   ├── not-found.tsx
│   ├── [slug]/
│   │   └── page.tsx          # /parts/[slug] — category OR part detail
│   │   └── [subcategory]/
│   │       └── page.tsx      # /parts/[slug]/[subcategory]
│   │       └── [brand]/
│   │           └── page.tsx  # /parts/[slug]/[subcategory]/[brand]
│   ├── [id]/                 # Part detail page (moved from catalog/)
│   │   ├── page.tsx          # (resolved from [slug] page via redirect)
│   │   ├── _components/
│   │   ├── _view-model/
│   │   └── ...
│   └── _components/
│       └── parts-catalog-client.tsx

├── brands/                   # NEW
│   ├── page.tsx              # /brands
│   └── [brand]/
│       ├── page.tsx          # /brands/[brand]
│       └── [category]/
│           ├── page.tsx      # /brands/[brand]/[category]
│           └── [subcategory]/
│               └── page.tsx  # /brands/[brand]/[category]/[subcategory]

├── inventory/
│   ├── (catalog)/
│   │   └── page.tsx          # /inventory
│   └── [category]/           # NEW
│       ├── page.tsx          # /inventory/[category]
│       └── not-found.tsx

lib/
├── catalog-taxonomy.ts       # NEW — category/subcategory/brand definitions
├── inventory-categories.ts   # NEW — equipment category definitions
├── catalog/
│   ├── fetch-catalog-by-taxonomy.ts  # NEW — unified data fetch
│   ├── catalog-search-params.ts      # updated (manufacturer -> brand)
│   └── inventory-search-params.ts    # updated (manufacturer -> brand)

components/
└── catalog/
    ├── category-hybrid-hero.tsx     # NEW
    ├── subcategory-nav.tsx          # NEW
    ├── taxonomy-breadcrumbs.tsx     # NEW
    ├── taxonomy-hero.tsx            # NEW
    └── catalog-bottom-cta.tsx       # NEW

11. SEO & Metadata

Each page generates generateMetadata() with:

  • title — SEO title from taxonomy
  • description — meta description from taxonomy
  • openGraph — OG title, description, images
  • alternates.canonical — canonical URL

Examples:

  • /parts/hydraulics -> "Hydraulics Parts | Pumps, Valves, Cylinders | CROP Prime"
  • /brands/new-holland -> "New Holland Parts | OEM Tractors & Equipment | CROP Prime"
  • /inventory/tractors -> from getInventoryCategoryBySlug("tractors").seoTitle

Static Generation:

// app/parts/[slug]/page.tsx
export function generateStaticParams() {
  return CATEGORY_SLUGS.map((slug) => ({ slug }));
}

5 categories are statically generated. Other pages use ISR (revalidate: 300s).


12. Development Guide

Adding a new category:

  1. Add object to MOCK_CATEGORIES in lib/catalog-taxonomy.ts
  2. Add slug to the CATEGORY_SLUGS array
  3. Add subcategories to MOCK_SUBCATEGORIES
  4. Optionally: add SVG to public/images/category/

Adding a new brand:

  1. Add object to MOCK_BRANDS in lib/catalog-taxonomy.ts
  2. Ensure vendorCode matches the API

Adding an equipment category:

  1. Add slug to INVENTORY_CATEGORY_SLUGS in lib/inventory-categories.ts
  2. Add metadata to MOCK_INVENTORY_CATEGORIES
// Correct (new format):
href="/parts"
href="/parts/hydraulics"
href="/parts/hydraulics/pumps"
href={`/parts/${partSku}`}
href="/brands/new-holland"
href="/inventory/tractors"

// Incorrect (old format, will redirect):
href="/catalog"           // 301 -> /parts
href="/catalog/ABC123"    // 301 -> /parts/ABC123
href="/hydraulics"        // 301 -> /parts/hydraulics

Query params:

// Correct (new names):
?brand=new-holland
?q=pump

// Incorrect (will redirect):
?manufacturer=NHL    // 301 -> ?brand=new-holland

13. Removed Files / Deprecated Code

  • app/catalog/ — fully removed (moved to app/parts/)
  • app/api/commerce/[...path]/route.ts — removed
  • services/ai-chat/commerce-api.ts — removed
  • services/ai-chat/utils.ts — removed
  • components/ai-input/chat-commerce.tsx — removed
  • components/ai-input/image-lightbox.tsx — removed
  • features/catalog/card-image-carousel.tsx — removed
  • features/catalog/filters/filter-multiselect-group.tsx — removed
  • features/catalog/filters/filter-show-more-button.tsx — removed
  • features/catalog/filters/slice-with-selected.ts — removed
  • features/product-detail/service-unavailable.tsx — removed
  • features/product-detail/try-again-button.tsx — removed
  • features/command-menu/model/use-command-menu-chat.ts — removed
  • lib/constants/cache.ts — removed
  • lib/constants/pagination.ts — removed
  • lib/utils/format-currency.ts — removed
  • cloudbuild.yaml / cloudbuild-deploy.yaml — removed
  • scripts/check-ci-health.sh — removed
  • scripts/check-env-parity.ts — removed
  • scripts/test-consultant-api.sh — removed
  • scripts/toggle-cloud-build.sh — removed
  • CLAUDE.md — removed (180 lines)

14. Other Changes (non-URL)

  • Cart summary and safety banner styles — updated colors to semantic tokens
  • AI chat — refactored, removed commerce-api, simplified client
  • Voice overlay — simplified
  • Search bar — refactored navigation and search hooks
  • Equipment filters — added new filters, refactored
  • Parts schematics — SVG viewer improvements, prediction API
  • Delivery API — updated client
  • Auth — updated sign-in/sign-up flow
  • Product detail — updated purchase panel, price display, media gallery, more-info sheet
  • CI/CD — updated GitHub Actions workflows, removed Cloud Build configs

On this page