npm package: @lebonplan/shared-address-selector
Description: React address selector component with GPS geolocation and Google Places autocomplete using Places API (New)
Author: LeBonPlan Team
Latest version: 1.3.3

# @lebonplan/shared-address-selector

Package React réutilisable pour la sélection d'adresse avec géolocalisation GPS et recherche Google Places.

**Utilise Places API (New) pour l'autocomplete et Geocoding API v3 (version standard) pour le reverse geocoding.**

## Installation

```bash
pnpm add @lebonplan/shared-address-selector
```

## Dépendances requises

- React 19.x
- React DOM 19.x
- Google Maps API Key (à configurer dans votre application)

## Utilisation

### Composant principal : AddressSelectorModal

```tsx
import { AddressSelectorModal, AddressSelectionData } from '@lebonplan/shared-address-selector';

function MyComponent() {
  const [isOpen, setIsOpen] = useState(false);
  const [selectedAddress, setSelectedAddress] = useState<AddressSelectionData | null>(null);

  const handleComplete = (address: AddressSelectionData) => {
    setSelectedAddress(address);
    // Transformer en CreateAddressDto pour l'API
    const dto = {
      placeId: address.googlePlaceId,
      latitude: address.latitude, // Toujours présent
      longitude: address.longitude, // Toujours présent
      accuracy: address.accuracy, // Toujours présent (GPS réel ou 50m)
      displayAddress: address.displayAddress,
      isCustomDisplayAddress: address.isCustomDisplayAddress,
    };
    // Envoyer à POST /addresses
  };

  return (
    <>
      <button onClick={() => setIsOpen(true)}>Sélectionner une adresse</button>
      <AddressSelectorModal
        isOpen={isOpen}
        onClose={() => setIsOpen(false)}
        onComplete={handleComplete}
        apiKey={process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY || ''}
        maxAccuracy={50} // Optionnel, 50m par défaut
      />
    </>
  );
}
```

## Flux utilisateur

Le composant suit un flux privilégiant la géolocalisation GPS :

1. **Ouverture automatique GPS** : À l'ouverture du modal, une tentative de géolocalisation GPS est lancée automatiquement
2. **Vérification de précision** : Si la précision est supérieure à `maxAccuracy` (50m par défaut), l'utilisateur est invité à réessayer ou rechercher manuellement
3. **En cas d'échec GPS** : Si la géolocalisation échoue (permission, timeout, etc.), l'utilisateur peut :
   - Réessayer la géolocalisation GPS
   - Rechercher manuellement via autocomplete Google Places
4. **Confirmation** : Une fois l'adresse obtenue (GPS ou recherche), l'utilisateur peut modifier l'adresse d'affichage avant de confirmer

### Composant d'affichage : AddressDisplay

```tsx
import { AddressDisplay, AddressSelectionData } from '@lebonplan/shared-address-selector';

function MyComponent() {
  const [address, setAddress] = useState<AddressSelectionData | null>(null);
  const [isModalOpen, setIsModalOpen] = useState(false);

  return (
    <AddressDisplay
      address={address}
      onEdit={() => setIsModalOpen(true)}
      showFormattedAddress={true} // Afficher l'adresse Google formatée si personnalisée (défaut: true)
    />
  );
}
```

**Props disponibles :**

- `address` : L'adresse à afficher (ou `null`)
- `onEdit` : Callback appelé lors du clic sur le bouton d'édition
- `className` : Classes CSS supplémentaires (optionnel)
- `showFormattedAddress` : Afficher l'adresse Google formatée quand l'adresse est personnalisée (défaut: `true`)

### Hook : useAddressSelector

```tsx
import { useAddressSelector, AddressSelectionData } from '@lebonplan/shared-address-selector';

function MyComponent() {
  const { isOpen, open, close, handleComplete } = useAddressSelector(address => {
    console.log('Address selected:', address);
  });

  return <button onClick={open}>Sélectionner une adresse</button>;
}
```

## Types

### AddressSelectionData

Type unifié représentant une adresse sélectionnée (GPS ou Google Places) :

```typescript
interface AddressSelectionData {
  type: 'google_place' | 'gps';
  googlePlaceId: string;
  latitude: number;
  longitude: number;
  accuracy: number; // Précision GPS réelle ou 50m pour Google Places
  formattedAddress: string;
  displayAddress: string;
  isCustomDisplayAddress: boolean;
  city: string; // Ville extraite depuis Google Places (depuis v1.2.0)
}
```

- `type: 'gps'` : Adresse obtenue via géolocalisation GPS (accuracy = précision réelle de l'appareil)
- `type: 'google_place'` : Adresse sélectionnée via recherche Google Places (accuracy = 50m par défaut)
- `city` : Ville extraite automatiquement depuis les `addressComponents` de Google Places (locality ou administrative_area_level_1)

## Intégration avec le backend

Le composant retourne `AddressSelectionData` qui doit être transformé en `CreateAddressDto` avant l'envoi à `POST /addresses` :

```typescript
const dto: CreateAddressDto = {
  placeId: addressData.googlePlaceId,
  latitude: addressData.latitude, // Toujours présent (GPS réel ou Google Places)
  longitude: addressData.longitude, // Toujours présent (GPS réel ou Google Places)
  accuracy: addressData.accuracy, // Toujours présent (GPS réel ou 50m pour Google Places)
  displayAddress: addressData.displayAddress,
  isCustomDisplayAddress: addressData.isCustomDisplayAddress,
  city: addressData.city, // Disponible depuis v1.2.0 (extrait automatiquement)
  // label et isDefault peuvent être ajoutés par l'app
};
```

**Note** : Le champ `city` est maintenant automatiquement extrait depuis les `addressComponents` de Google Places lors de la sélection d'une adresse (via GPS ou recherche manuelle).

## Configuration

### Props du composant AddressSelectorModal

- `isOpen` : État d'ouverture du modal (requis)
- `onClose` : Callback appelé lors de la fermeture (requis)
- `onComplete` : Callback appelé avec `AddressSelectionData` lors de la confirmation (requis)
- `apiKey` : Clé API Google Maps (requis)
- `maxAccuracy` (optionnel, défaut: 50) : Précision maximale acceptée en mètres pour la géolocalisation GPS. Si la précision est supérieure, l'utilisateur devra réessayer ou rechercher manuellement.

### Améliorations UX (v1.2.0+)

- **Modal responsive** : Le modal s'adapte à différentes tailles d'écran avec un layout flex et scrollable
- **Gestion améliorée du displayAddress** : L'adresse d'affichage peut être modifiée indépendamment de l'adresse formatée
- **Meilleure lisibilité** : Amélioration des styles et de la hiérarchie visuelle dans tous les composants
- **Extraction automatique de la ville** : Le champ `city` est maintenant automatiquement extrait depuis Google Places

### Variables d'environnement

- `NEXT_PUBLIC_GOOGLE_MAPS_API_KEY` : Clé API Google Maps (requise)

### Permissions navigateur

Pour la géolocalisation GPS, l'utilisateur doit autoriser l'accès à sa position. Le composant gère automatiquement les cas d'erreur (permission refusée, timeout, etc.).

## Structure

```
packages/shared-address-selector/
├── src/
│   ├── types/
│   │   └── address-selection.types.ts (contient AddressSelectionData avec champ city)
│   ├── hooks/
│   │   ├── useGeolocation.ts
│   │   ├── useGooglePlaces.ts (utilise Places API New - REST, optimisé avec gestion d'erreurs)
│   │   └── useAddressSelector.ts
│   ├── components/
│   │   ├── AddressSelectorModal.tsx (utilise Geocoding API New - REST, UX améliorée)
│   │   ├── AddressConfirmationScreen.tsx (UX améliorée avec meilleure gestion du displayAddress)
│   │   └── AddressDisplay.tsx (lisibilité améliorée, option showFormattedAddress)
│   └── index.ts
```

## Changelog

### v1.3.0 (publié)

- Publication sur npm

### v1.2.0

- ✨ **Nouveau champ `city`** : Extraction automatique de la ville depuis Google Places
- 🎨 **Amélioration UX des composants** :
  - Modal responsive avec layout flex et scrollable
  - Meilleure gestion du `displayAddress` dans `AddressConfirmationScreen`
  - Amélioration de la lisibilité dans `AddressDisplay` avec option `showFormattedAddress`
  - Styles améliorés et hiérarchie visuelle optimisée
- ⚡ **Optimisation `useGooglePlaces`** :
  - Gestion améliorée des erreurs avec AbortController
  - Optimisation des appels API avec annulation des requêtes précédentes
  - Meilleure gestion des timeouts et erreurs réseau

### v1.1.0

- Version initiale avec fonctionnalités de base

## Développement

```bash
# Build
pnpm build

# Watch mode
pnpm dev

# Clean
pnpm clean

# Type check
pnpm type-check
```

## Publication sur npm

### Prérequis

1. Être connecté à npm : `npm login`
2. Avoir les droits de publication sur le scope `@lebonplan`

### Scripts de publication

```bash
# Bump de version patch (1.0.0 -> 1.0.1)
pnpm publish:patch

# Bump de version minor (1.0.0 -> 1.1.0)
pnpm publish:minor

# Bump de version major (1.0.0 -> 2.0.0)
pnpm publish:major

# Test de publication (dry-run)
pnpm publish:dry-run
```

Les scripts de publication effectuent automatiquement :

1. Bump de version dans `package.json`
2. Build du package
3. Publication sur npm avec `--access public` (nécessaire pour les scoped packages publics)

### Bump de version manuel

Si vous voulez juste bump la version sans publier :

```bash
# Patch
pnpm version:patch

# Minor
pnpm version:minor

# Major
pnpm version:major
```