> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/No-Country-simulation/S02-26-Equipo-33-Web-App/llms.txt
> Use this file to discover all available pages before exploring further.

# Marketplace

> Browse, filter, and discover premium horses with advanced search and filtering capabilities

## Overview

The Horse Trust marketplace provides a luxury horse browsing experience with advanced filtering, sorting, and real-time search capabilities. The marketplace is implemented as a server-side rendered page with client-side interactivity.

## Architecture

The marketplace uses a hybrid rendering approach:

### Server Component (`marketplace/page.tsx`)

```typescript theme={null}
export const dynamic = 'force-dynamic';

async function getHorses() {
  try {
    const apiUrl = process.env.NEXT_PUBLIC_API_URL;
    
    const res = await fetch(`${apiUrl}/horses`, {
      next: { revalidate: 60 } // Revalidate every 60 seconds
    });

    if (!res.ok) throw new Error('Error al traer los caballos');

    const jsonResponse = await res.json();
    const horsesArray = Array.isArray(jsonResponse) ? jsonResponse : jsonResponse.data;

    if (!horsesArray || !Array.isArray(horsesArray)) return [];
    
    return horsesArray;
  } catch (error) {
    console.error("Hubo un problema conectando con el backend:", error);
    return [];
  }
}

export default async function MarketplacePage() {
  const initialHorses = await getHorses();
  return <MarketplaceClient initialHorses={initialHorses} />;
}
```

<Info>
  The marketplace uses **ISR (Incremental Static Regeneration)** with 60-second revalidation for optimal performance.
</Info>

### Client Component (`MarketplaceClient.tsx`)

Handles interactive filtering and sorting:

```typescript theme={null}
interface Horse {
  ID: number;
  NAME: string;
  AGE: number;
  BREED: string;
  DISCIPLINE: string;
  LOCATION: string;
  PRICE: number;
  STATUS: string;
  SELLER_NAME: string;
  SELLER_VERIFIED: string;
  MAIN_PHOTO: string;
}

export default function MarketplaceClient({ initialHorses }: { initialHorses: Horse[] }) {
  const [filters, setFilters] = useState(defaultFilters);
  const [sortBy, setSortBy] = useState('nuevos');
  
  // Filter and sort logic...
}
```

## Filtering System

The marketplace implements a comprehensive filtering engine:

### Default Filters

```typescript theme={null}
const defaultFilters = {
  minPrice: '',
  maxPrice: '',
  breed: 'Todas las Razas',
  disciplines: [] as string[],
  location: '',
  verifiedOnly: false
};
```

### Filter Logic

<Tabs>
  <Tab title="Price Range">
    ```typescript theme={null}
    if (filters.minPrice !== '' && horse.PRICE < Number(filters.minPrice)) 
      return false;

    if (filters.maxPrice !== '' && horse.PRICE > Number(filters.maxPrice)) 
      return false;
    ```
  </Tab>

  <Tab title="Breed Filter">
    ```typescript theme={null}
    if (
      filters.breed !== 'Todas las Razas' && 
      horse.BREED.toLowerCase().trim() !== filters.breed.toLowerCase().trim()
    ) {
      return false;
    }
    ```
  </Tab>

  <Tab title="Discipline">
    ```typescript theme={null}
    if (filters.disciplines.length > 0 && 
        !filters.disciplines.includes(horse.DISCIPLINE)) 
      return false;
    ```
  </Tab>

  <Tab title="Location Search">
    ```typescript theme={null}
    if (filters.location && 
        !horse.LOCATION.toLowerCase().includes(filters.location.toLowerCase())) 
      return false;
    ```
  </Tab>

  <Tab title="Verified Sellers">
    ```typescript theme={null}
    if (filters.verifiedOnly && horse.SELLER_VERIFIED !== 'verified') 
      return false;
    ```
  </Tab>
</Tabs>

## Sorting Options

The marketplace supports three sorting modes:

```typescript theme={null}
const sortedHorses = [...filteredHorses].sort((a, b) => {
  if (sortBy === 'precio_asc') {
    return a.PRICE - b.PRICE; // Low to High
  }
  if (sortBy === 'precio_desc') {
    return b.PRICE - a.PRICE; // High to Low
  }
  return b.ID - a.ID; // Newest First (default)
});
```

<CardGroup cols={3}>
  <Card title="Newest First" icon="clock">
    Default sort showing latest listings first
  </Card>

  <Card title="Price: Low to High" icon="arrow-up-1-9">
    Affordable horses first
  </Card>

  <Card title="Price: High to Low" icon="arrow-down-9-1">
    Premium horses first
  </Card>
</CardGroup>

## Filter Sidebar

The `FilterSideBar` component provides an intuitive filtering interface:

```tsx theme={null}
<FilterSideBar 
  filters={filters} 
  setFilters={setFilters} 
  clearFilters={clearFilters} 
/>
```

### Key Features

* **Price Range Slider**: Visual price range selection
* **Breed Dropdown**: All supported breeds
* **Multi-Discipline**: Select multiple disciplines
* **Location Search**: Text-based location filtering
* **Verified Badge**: Toggle to show only verified sellers
* **Clear All**: Reset filters with one click

## Horse Card Component

Each listing is displayed using the `HorseCard` component:

```tsx theme={null}
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
  {sortedHorses.map(horse => (
    <HorseCard key={horse.ID} horse={horse} />
  ))}
</div>
```

### Card Information Display

<Steps>
  <Step title="Hero Image">
    Large cover photo with verified seller badge overlay
  </Step>

  <Step title="Horse Details">
    Name, breed, age, and discipline prominently displayed
  </Step>

  <Step title="Location">
    Geographic location with map pin icon
  </Step>

  <Step title="Pricing">
    Price with currency, formatted with locale-specific separators
  </Step>

  <Step title="Seller Info">
    Seller name with verification status badge
  </Step>
</Steps>

## Responsive Design

The marketplace adapts seamlessly across devices:

<Tabs>
  <Tab title="Desktop (xl)">
    * 3-column grid layout
    * Sidebar always visible
    * Full filter controls
  </Tab>

  <Tab title="Tablet (md)">
    * 2-column grid layout
    * Collapsible sidebar
    * Compact filters
  </Tab>

  <Tab title="Mobile">
    * Single column layout
    * Bottom sheet filters
    * Touch-optimized controls
  </Tab>
</Tabs>

## Search Results

The marketplace displays search result counts and handles empty states:

```tsx theme={null}
<div className="flex justify-between mb-8">
  <div>
    <h1 className="text-3xl font-black">Colecciones de Lujo</h1>
    <p className="text-slate-500">
      {sortedHorses.length} caballos disponibles
    </p>
  </div>
  
  <select value={sortBy} onChange={(e) => setSortBy(e.target.value)}>
    <option value="nuevos">Nuevos Ingresos</option>
    <option value="precio_asc">Precio: Menor a Mayor</option>
    <option value="precio_desc">Precio: Mayor a Menor</option>
  </select>
</div>

{sortedHorses.length === 0 ? (
  <div className="text-center py-20 border-2 border-dashed">
    No se encontraron ejemplares con los filtros seleccionados.
  </div>
) : (
  <HorseGrid horses={sortedHorses} />
)}
```

## Pagination

The marketplace includes pagination controls (currently static, can be enhanced):

```tsx theme={null}
{sortedHorses.length > 0 && (
  <div className="mt-12 flex items-center justify-center gap-2">
    <button className="size-10 rounded-lg border">
      <ChevronLeft className="w-4 h-4" />
    </button>
    <button className="size-10 bg-equestrian-navy text-white font-bold">1</button>
    <button className="size-10 rounded-lg border">2</button>
    <span className="px-2 text-slate-400">...</span>
    <button className="size-10 rounded-lg border">
      <ChevronRight className="w-4 h-4" />
    </button>
  </div>
)}
```

<Tip>
  Consider implementing server-side pagination for marketplaces with 100+ listings to improve performance.
</Tip>

## Performance Optimizations

<AccordionGroup>
  <Accordion title="Server-Side Rendering">
    Initial page load is server-rendered for instant content display and SEO benefits.
  </Accordion>

  <Accordion title="Incremental Static Regeneration">
    Pages are cached and revalidated every 60 seconds, balancing freshness and speed.
  </Accordion>

  <Accordion title="Client-Side Filtering">
    All filtering and sorting happens client-side for instant feedback without network requests.
  </Accordion>

  <Accordion title="Image Optimization">
    Cloudinary handles image optimization, resizing, and CDN delivery automatically.
  </Accordion>
</AccordionGroup>

## User Experience Features

### Visual Hierarchy

```tsx theme={null}
<main className="mx-auto flex max-w-[1440px] px-6 py-8 lg:px-12 gap-8">
  <FilterSideBar /> {/* Left sidebar */}
  <div className="flex-1"> {/* Main content area */}
    <Toolbar />
    <HorseGrid />
    <Pagination />
  </div>
</main>
```

### Verified Seller Badges

Verified sellers receive prominent visual indicators:

```tsx theme={null}
{horse.SELLER_VERIFIED === 'verified' && (
  <div className="absolute top-4 right-4">
    <ShieldCheck className="w-6 h-6 text-equestrian-gold" />
  </div>
)}
```

## Accessibility

<CardGroup cols={2}>
  <Card title="Keyboard Navigation" icon="keyboard">
    Full keyboard support for filters and sorting
  </Card>

  <Card title="Screen Readers" icon="ear-listen">
    Semantic HTML and ARIA labels throughout
  </Card>

  <Card title="Focus Management" icon="bullseye">
    Clear focus indicators on all interactive elements
  </Card>

  <Card title="Alt Text" icon="image">
    Descriptive alt text for all horse images
  </Card>
</CardGroup>

## Error Handling

The marketplace gracefully handles API failures:

```typescript theme={null}
async function getHorses() {
  try {
    const res = await fetch(`${apiUrl}/horses`, {
      next: { revalidate: 60 }
    });

    if (!res.ok) throw new Error('Error al traer los caballos');

    const jsonResponse = await res.json();
    return Array.isArray(jsonResponse) ? jsonResponse : jsonResponse.data;
  } catch (error) {
    console.error("Hubo un problema conectando con el backend:", error);
    return []; // Return empty array on error
  }
}
```

## Next Steps

<CardGroup cols={2}>
  <Card title="View Listing Details" icon="eye" href="/features/horse-listings">
    Learn about individual horse listing pages
  </Card>

  <Card title="Contact Sellers" icon="message" href="/features/real-time-chat">
    Start conversations with sellers
  </Card>
</CardGroup>
