# `@ta-interaktiv/react-municipality-search`

A React component for searching Swiss municipalities by name or postal code (ZIP). The component provides autocomplete functionality with smart ranking, supports multiple locales (DE/FR), and can remember previously selected municipalities.

## Installation

```bash
bun add @ta-interaktiv/react-municipality-search
```

## Usage

```tsx
import { MunicipalitySearch } from '@ta-interaktiv/react-municipality-search';

function MyComponent() {
  const handleSelection = (municipality) => {
    console.log('Selected:', municipality.NORMGEMEINDE, municipality.PLZ4);
  };

  return (
    <MunicipalitySearch
      municipalityData="2021v3"
      locale="de"
      onSelectionHandler={handleSelection}
    />
  );
}
```

## Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `municipalityData` | `string` | `"2021v3"` | Which year/version of municipality data to use (see [available data](https://interaktiv-mf.tagesanzeiger.ch/municipality-data/index.html)) |
| `locale` | `"de" \| "fr"` | `"de"` | Locale for UI strings |
| `onSelectionHandler` | `(municipality: Municipality) => void` | *required* | Callback when user selects a municipality |
| `placeholder` | `string` | *(locale-based)* | Placeholder text for the search input |
| `dedupe` | `boolean` | `false` | Deduplicate municipalities by name (ignoring ZIP) |
| `resetOnSelect` | `boolean` | `false` | Reset the search after selection |
| `iconOnRightSide` | `boolean` | `false` | Position search icon on the right side |
| `maxResults` | `number` | `10` | Maximum number of results to display |
| `customMunicipalities` | `Municipality[]` | `undefined` | Use custom municipality data instead of fetching |
| `selectedMunicipality` | `Municipality` | `undefined` | Pre-selected municipality (read-only mode) |
| `selectedMunicipalityId` | `number` | `undefined` | GDENR of pre-selected municipality |
| `onCloseHandler` | `() => void` | `undefined` | Handler for close button in pre-selected mode |
| `inputBackgroundColor` | `string` | `"var(--site-background)"` | Background color of input field |
| `resultBackgroundColor` | `string` | `"var(--site-background)"` | Background color of results dropdown |
| `propertyToSearch` | `keyof Municipality` | `"NORMGEMEINDE"` | Which municipality property to search (must be string) |

## Available Municipality Data

View all available municipality data files and versions at:  
**https://interaktiv-mf.tagesanzeiger.ch/municipality-data/index.html**

Available data includes:
- Year-specific datasets (e.g., `20230101_de`, `20240101_fr`)
- Latest versions (`latest_de`, `latest_fr`)
- Custom regional datasets (e.g., `24h_municipalities`, `zrz_municipalities`)
- Versions with/without ZIP codes (`_nozip` suffix)

## Municipality Type

```typescript
interface Municipality {
  GDENR: number;          // Municipality number (BFS-Nr)
  ORTNAME?: string;       // Place name
  PLZ4?: number;          // 4-digit postal code
  PLZ6?: number;          // 6-digit postal code
  GDENAMK?: string;       // Short municipality name
  KTKZ: string;           // Canton abbreviation
  NORMORTSNAME?: string;  // Normalized place name
  NORMGEMEINDE: string;   // Normalized municipality name
  URL?: string;           // Optional URL
}
```

## Search Behavior

- **By ZIP code**: Enter numbers (e.g., "8000" or "3000") to search postal codes
- **By name**: Enter letters (e.g., "Zürich" or "Bern") to search municipality/place names
- Results are ranked by relevance: exact matches first, then word matches, then partial matches
- Minimum 2 characters required to trigger search
